Merge "Converted NewUserResponse constructor to testAPI"
diff --git a/Android.bp b/Android.bp
index acd3b34..d64951c 100644
--- a/Android.bp
+++ b/Android.bp
@@ -160,6 +160,7 @@
         "android.net.ipsec.ike.stubs.module_lib",
         "framework-appsearch.stubs.module_lib",
         "framework-connectivity.stubs.module_lib",
+        "framework-connectivity-tiramisu.stubs.module_lib",
         "framework-graphics.stubs.module_lib",
         "framework-media.stubs.module_lib",
         "framework-mediaprovider.stubs.module_lib",
@@ -171,6 +172,7 @@
         "framework-supplementalprocess.stubs.module_lib",
         "framework-tethering.stubs.module_lib",
         "framework-uwb.stubs.module_lib",
+        "framework-nearby.stubs.module_lib",
         "framework-wifi.stubs.module_lib",
     ],
     soong_config_variables: {
@@ -192,6 +194,7 @@
         "framework-minus-apex",
         "framework-appsearch.impl",
         "framework-connectivity.impl",
+        "framework-connectivity-tiramisu.impl",
         "framework-graphics.impl",
         "framework-mediaprovider.impl",
         "framework-permission.impl",
@@ -201,6 +204,7 @@
         "framework-statsd.impl",
         "framework-supplementalprocess.impl",
         "framework-tethering.impl",
+        "framework-nearby.impl",
         "framework-uwb.impl",
         "framework-wifi.impl",
         "updatable-media",
diff --git a/ApiDocs.bp b/ApiDocs.bp
index 7a4ef2a..feb43d1 100644
--- a/ApiDocs.bp
+++ b/ApiDocs.bp
@@ -118,6 +118,7 @@
     srcs: [
         ":framework-appsearch-sources",
         ":framework-connectivity-sources",
+        ":framework-connectivity-tiramisu-updatable-sources",
         ":framework-graphics-srcs",
         ":framework-mediaprovider-sources",
         ":framework-nearby-sources",
@@ -164,6 +165,7 @@
         ":android.net.ipsec.ike{.public.stubs.source}",
         ":framework-appsearch{.public.stubs.source}",
         ":framework-connectivity{.public.stubs.source}",
+        ":framework-connectivity-tiramisu{.public.stubs.source}",
         ":framework-graphics{.public.stubs.source}",
         ":framework-media{.public.stubs.source}",
         ":framework-mediaprovider{.public.stubs.source}",
@@ -204,6 +206,7 @@
         ":art.module.public.api{.public.annotations.zip}",
         ":framework-appsearch{.public.annotations.zip}",
         ":framework-connectivity{.public.annotations.zip}",
+        ":framework-connectivity-tiramisu{.public.annotations.zip}",
         ":framework-graphics{.public.annotations.zip}",
         ":framework-media{.public.annotations.zip}",
         ":framework-mediaprovider{.public.annotations.zip}",
diff --git a/MULTIUSER_OWNERS b/MULTIUSER_OWNERS
index fbc611a..9d92e0f 100644
--- a/MULTIUSER_OWNERS
+++ b/MULTIUSER_OWNERS
@@ -1,4 +1,5 @@
 # OWNERS of Multiuser related files
 bookatz@google.com
+olilan@google.com
 omakoto@google.com
 yamasani@google.com
diff --git a/StubLibraries.bp b/StubLibraries.bp
index 9543fbd..1e16f94 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -67,19 +67,13 @@
     },
     dists: [
         {
-            targets: [
-                "sdk",
-                "win_sdk",
-            ],
+            targets: ["sdk"],
             dir: "apistubs/android/public/api",
             dest: "android-non-updatable.txt",
             tag: ".api.txt",
         },
         {
-            targets: [
-                "sdk",
-                "win_sdk",
-            ],
+            targets: ["sdk"],
             dir: "apistubs/android/public/api",
             dest: "android-non-updatable-removed.txt",
             tag: ".removed-api.txt",
@@ -123,19 +117,13 @@
     },
     dists: [
         {
-            targets: [
-                "sdk",
-                "win_sdk",
-            ],
+            targets: ["sdk"],
             dir: "apistubs/android/system/api",
             dest: "android-non-updatable.txt",
             tag: ".api.txt",
         },
         {
-            targets: [
-                "sdk",
-                "win_sdk",
-            ],
+            targets: ["sdk"],
             dir: "apistubs/android/system/api",
             dest: "android-non-updatable-removed.txt",
             tag: ".removed-api.txt",
@@ -159,37 +147,25 @@
     },
     dists: [
         {
-            targets: [
-                "sdk",
-                "win_sdk",
-            ],
+            targets: ["sdk"],
             dir: "apistubs/android/test/api",
             dest: "android.txt",
             tag: ".api.txt",
         },
         {
-            targets: [
-                "sdk",
-                "win_sdk",
-            ],
+            targets: ["sdk"],
             dir: "apistubs/android/test/api",
             dest: "removed.txt",
             tag: ".removed-api.txt",
         },
         {
-            targets: [
-                "sdk",
-                "win_sdk",
-            ],
+            targets: ["sdk"],
             dir: "apistubs/android/test/api",
             dest: "android-non-updatable.txt",
             tag: ".api.txt",
         },
         {
-            targets: [
-                "sdk",
-                "win_sdk",
-            ],
+            targets: ["sdk"],
             dir: "apistubs/android/test/api",
             dest: "android-non-updatable-removed.txt",
             tag: ".removed-api.txt",
@@ -218,19 +194,13 @@
     },
     dists: [
         {
-            targets: [
-                "sdk",
-                "win_sdk",
-            ],
+            targets: ["sdk"],
             dir: "apistubs/android/module-lib/api",
             dest: "android-non-updatable.txt",
             tag: ".api.txt",
         },
         {
-            targets: [
-                "sdk",
-                "win_sdk",
-            ],
+            targets: ["sdk"],
             dir: "apistubs/android/module-lib/api",
             dest: "android-non-updatable-removed.txt",
             tag: ".removed-api.txt",
@@ -249,6 +219,7 @@
     "conscrypt.module.public.api.stubs",
     "framework-appsearch.stubs",
     "framework-connectivity.stubs",
+    "framework-connectivity-tiramisu.stubs",
     "framework-graphics.stubs",
     "framework-media.stubs",
     "framework-mediaprovider.stubs",
@@ -271,6 +242,7 @@
     "conscrypt.module.public.api.stubs", // Only has public stubs
     "framework-appsearch.stubs.system",
     "framework-connectivity.stubs.system",
+    "framework-connectivity-tiramisu.stubs.system",
     "framework-graphics.stubs.system",
     "framework-media.stubs.system",
     "framework-mediaprovider.stubs.system",
@@ -296,10 +268,7 @@
     java_version: "1.8",
     compile_dex: true,
     dist: {
-        targets: [
-            "sdk",
-            "win_sdk",
-        ],
+        targets: ["sdk"],
         tag: ".jar",
         dest: "android-non-updatable.jar",
     },
@@ -376,10 +345,7 @@
 java_defaults {
     name: "android_stubs_dists_default",
     dist: {
-        targets: [
-            "sdk",
-            "win_sdk",
-        ],
+        targets: ["sdk"],
         tag: ".jar",
         dest: "android.jar",
     },
@@ -425,10 +391,7 @@
     dists: [
         {
             // Legacy dist path
-            targets: [
-                "sdk",
-                "win_sdk",
-            ],
+            targets: ["sdk"],
             tag: ".jar",
             dest: "android_system.jar",
         },
@@ -468,6 +431,7 @@
     static_libs: [
         "android-non-updatable.stubs.module_lib",
         "art.module.public.api.stubs.module_lib",
+        "i18n.module.public.api.stubs",
     ],
     dist: {
         dir: "apistubs/android/module-lib",
diff --git a/TEST_MAPPING b/TEST_MAPPING
index c5c6012..81e4fcb 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -17,6 +17,19 @@
   ],
   "presubmit": [
     {
+      "file_patterns": [
+        "ApexManager\\.java",
+        "SystemServer\\.java",
+        "services/tests/apexsystemservices/.*"
+      ],
+      "name": "ApexSystemServicesTestCases",
+      "options": [
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        }
+      ]
+    },
+    {
       "name": "FrameworksUiServicesTests",
       "options": [
         {
diff --git a/apct-tests/perftests/core/src/android/view/HandwritingInitiatorPerfTest.java b/apct-tests/perftests/core/src/android/view/HandwritingInitiatorPerfTest.java
new file mode 100644
index 0000000..cf94e9e
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/view/HandwritingInitiatorPerfTest.java
@@ -0,0 +1,235 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.MotionEvent.ACTION_DOWN;
+import static android.view.MotionEvent.ACTION_MOVE;
+import static android.view.MotionEvent.ACTION_UP;
+import static android.view.MotionEvent.TOOL_TYPE_FINGER;
+import static android.view.MotionEvent.TOOL_TYPE_STYLUS;
+
+
+import android.app.Instrumentation;
+import android.content.Context;
+import android.graphics.Rect;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodManager;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Benchmark tests for {@link HandwritingInitiator}
+ *
+ * Build/Install/Run:
+ * atest CorePerfTests:android.view.HandwritingInitiatorPerfTest
+ */
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class HandwritingInitiatorPerfTest {
+    private Context mContext;
+    private HandwritingInitiator mHandwritingInitiator;
+    private int mTouchSlop;
+
+    @Rule
+    public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+    @Before
+    public void setup() {
+        final Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mContext = mInstrumentation.getTargetContext();
+        ViewConfiguration viewConfiguration = ViewConfiguration.get(mContext);
+        mTouchSlop = viewConfiguration.getScaledTouchSlop();
+        InputMethodManager inputMethodManager = mContext.getSystemService(InputMethodManager.class);
+        mHandwritingInitiator = new HandwritingInitiator(viewConfiguration, inputMethodManager);
+    }
+
+    @Test
+    public void onTouchEvent_actionDown_toolTypeStylus() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        final MotionEvent downEvent =
+                createMotionEvent(ACTION_DOWN, TOOL_TYPE_STYLUS, 10, 10, 0);
+        final MotionEvent upEvent =
+                createMotionEvent(ACTION_UP, TOOL_TYPE_STYLUS, 11, 11, 1);
+
+        while (state.keepRunning()) {
+            mHandwritingInitiator.onTouchEvent(downEvent);
+            state.pauseTiming();
+            mHandwritingInitiator.onTouchEvent(upEvent);
+            state.resumeTiming();
+        }
+    }
+
+    @Test
+    public void onTouchEvent_actionUp_toolTypeStylus() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        final MotionEvent downEvent =
+                createMotionEvent(ACTION_DOWN, TOOL_TYPE_STYLUS, 10, 10, 0);
+        final MotionEvent upEvent =
+                createMotionEvent(ACTION_UP, TOOL_TYPE_STYLUS, 11, 11, 1);
+
+        while (state.keepRunning()) {
+            state.pauseTiming();
+            mHandwritingInitiator.onTouchEvent(downEvent);
+            state.resumeTiming();
+            mHandwritingInitiator.onTouchEvent(upEvent);
+        }
+    }
+
+    @Test
+    public void onTouchEvent_actionMove_toolTypeStylus() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        final int initX = 10;
+        final int initY = 10;
+        final MotionEvent downEvent =
+                createMotionEvent(ACTION_DOWN, TOOL_TYPE_STYLUS, initX, initY, 0);
+
+        final int x = initX + mTouchSlop;
+        final int y = initY + mTouchSlop;
+        final MotionEvent moveEvent =
+                createMotionEvent(ACTION_MOVE, TOOL_TYPE_STYLUS, x, y, 1);
+        final MotionEvent upEvent =
+                createMotionEvent(ACTION_UP, TOOL_TYPE_STYLUS, x, y, 1);
+
+        while (state.keepRunning()) {
+            state.pauseTiming();
+            mHandwritingInitiator.onTouchEvent(downEvent);
+            state.resumeTiming();
+
+            mHandwritingInitiator.onTouchEvent(moveEvent);
+
+            state.pauseTiming();
+            mHandwritingInitiator.onTouchEvent(upEvent);
+            state.resumeTiming();
+        }
+    }
+
+    @Test
+    public void onTouchEvent_actionDown_toolTypeFinger() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        final MotionEvent downEvent =
+                createMotionEvent(ACTION_DOWN, TOOL_TYPE_FINGER, 10, 10, 0);
+        final MotionEvent upEvent =
+                createMotionEvent(ACTION_UP, TOOL_TYPE_FINGER, 11, 11, 1);
+
+        while (state.keepRunning()) {
+            mHandwritingInitiator.onTouchEvent(downEvent);
+            mHandwritingInitiator.onTouchEvent(upEvent);
+        }
+    }
+
+    @Test
+    public void onTouchEvent_actionUp_toolTypeFinger() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        final MotionEvent downEvent =
+                createMotionEvent(ACTION_DOWN, TOOL_TYPE_FINGER, 10, 10, 0);
+        final MotionEvent upEvent =
+                createMotionEvent(ACTION_UP, TOOL_TYPE_FINGER, 11, 11, 1);
+
+        while (state.keepRunning()) {
+            mHandwritingInitiator.onTouchEvent(downEvent);
+            state.pauseTiming();
+            mHandwritingInitiator.onTouchEvent(upEvent);
+            state.resumeTiming();
+        }
+    }
+
+    @Test
+    public void onTouchEvent_actionMove_toolTypeFinger() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        final int initX = 10;
+        final int initY = 10;
+        final MotionEvent downEvent =
+                createMotionEvent(ACTION_DOWN, TOOL_TYPE_FINGER, initX, initY, 0);
+
+        final int x = initX + mTouchSlop;
+        final int y = initY + mTouchSlop;
+        final MotionEvent moveEvent =
+                createMotionEvent(ACTION_MOVE, TOOL_TYPE_FINGER, x, y, 1);
+        final MotionEvent upEvent =
+                createMotionEvent(ACTION_UP, TOOL_TYPE_FINGER, x, y, 1);
+
+        while (state.keepRunning()) {
+            state.pauseTiming();
+            mHandwritingInitiator.onTouchEvent(downEvent);
+            state.resumeTiming();
+
+            mHandwritingInitiator.onTouchEvent(moveEvent);
+
+            state.pauseTiming();
+            mHandwritingInitiator.onTouchEvent(upEvent);
+            state.resumeTiming();
+        }
+    }
+
+    @Test
+    public void onInputConnectionCreated() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        final View view = new View(mContext);
+        final EditorInfo editorInfo = new EditorInfo();
+        while (state.keepRunning()) {
+            mHandwritingInitiator.onInputConnectionCreated(view, editorInfo);
+            state.pauseTiming();
+            mHandwritingInitiator.onInputConnectionClosed(view);
+            state.resumeTiming();
+        }
+    }
+
+    @Test
+    public void onInputConnectionClosed() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        final View view = new View(mContext);
+        final EditorInfo editorInfo = new EditorInfo();
+        while (state.keepRunning()) {
+            state.pauseTiming();
+            mHandwritingInitiator.onInputConnectionCreated(view, editorInfo);
+            state.resumeTiming();
+            mHandwritingInitiator.onInputConnectionClosed(view);
+        }
+    }
+
+    @Test
+    public void updateEditorBoundary() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        final Rect rect = new Rect(0, 0, 100, 100);
+        while (state.keepRunning()) {
+            mHandwritingInitiator.updateEditorBound(rect);
+        }
+    }
+
+    private MotionEvent createMotionEvent(int action, int toolType, int x, int y, long eventTime) {
+        MotionEvent.PointerProperties[] properties = MotionEvent.PointerProperties.createArray(1);
+        properties[0].toolType = toolType;
+
+        MotionEvent.PointerCoords[] coords = MotionEvent.PointerCoords.createArray(1);
+        coords[0].x = x;
+        coords[0].y = y;
+
+        return MotionEvent.obtain(0 /* downTime */, eventTime /* eventTime */, action, 1,
+                properties, coords, 0 /* metaState */, 0 /* buttonState */, 1 /* xPrecision */,
+                1 /* yPrecision */, 0 /* deviceId */, 0 /* edgeFlags */,
+                InputDevice.SOURCE_TOUCHSCREEN, 0 /* flags */);
+    }
+}
diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/TestPackageInstaller.java b/apct-tests/perftests/utils/src/android/perftests/utils/TestPackageInstaller.java
index 530dc9d..15a65ce 100644
--- a/apct-tests/perftests/utils/src/android/perftests/utils/TestPackageInstaller.java
+++ b/apct-tests/perftests/utils/src/android/perftests/utils/TestPackageInstaller.java
@@ -130,7 +130,8 @@
         IntentSender getIntentSender(int sessionId) {
             String action = BROADCAST_ACTION + "." + sessionId;
             IntentFilter filter = new IntentFilter(action);
-            mContext.registerReceiver(this, filter);
+            mContext.registerReceiver(this, filter,
+                    Context.RECEIVER_EXPORTED_UNAUDITED);
 
             Intent intent = new Intent(action);
             PendingIntent pending = PendingIntent.getBroadcast(mContext, sessionId, intent,
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobService.java b/apex/jobscheduler/framework/java/android/app/job/JobService.java
index c251529a..e5b0742 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobService.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobService.java
@@ -125,7 +125,7 @@
      * will not be invoked.
      *
      * @param params Parameters specifying info about this job, including the optional
-     *     extras configured with {@link JobInfo.Builder#setExtras(android.os.PersistableBundle).
+     *     extras configured with {@link JobInfo.Builder#setExtras(android.os.PersistableBundle)}.
      *     This object serves to identify this specific running job instance when calling
      *     {@link #jobFinished(JobParameters, boolean)}.
      * @return {@code true} if your service will continue running, using a separate thread
diff --git a/apex/media/framework/jarjar_rules.txt b/apex/media/framework/jarjar_rules.txt
index 91489dc..1bd5b36 100644
--- a/apex/media/framework/jarjar_rules.txt
+++ b/apex/media/framework/jarjar_rules.txt
@@ -1,2 +1,4 @@
 rule com.android.modules.** android.media.internal.@1
 rule com.google.android.exoplayer2.** android.media.internal.exo.@1
+rule com.google.common.** android.media.internal.guava_common.@1
+rule com.google.thirdparty.** android.media.internal.guava_thirdparty.@1
diff --git a/apex/media/framework/java/android/media/MediaCommunicationManager.java b/apex/media/framework/java/android/media/MediaCommunicationManager.java
index 8ee9616..ef5552e 100644
--- a/apex/media/framework/java/android/media/MediaCommunicationManager.java
+++ b/apex/media/framework/java/android/media/MediaCommunicationManager.java
@@ -36,6 +36,8 @@
 
 import androidx.annotation.RequiresApi;
 
+import androidx.annotation.RequiresApi;
+
 import com.android.internal.annotations.GuardedBy;
 import com.android.modules.annotation.MinSdk;
 import com.android.modules.utils.build.SdkLevel;
diff --git a/apex/media/framework/java/android/media/MediaParser.java b/apex/media/framework/java/android/media/MediaParser.java
index b6f85c7..7daebd0 100644
--- a/apex/media/framework/java/android/media/MediaParser.java
+++ b/apex/media/framework/java/android/media/MediaParser.java
@@ -62,8 +62,8 @@
 import com.google.android.exoplayer2.upstream.DataReader;
 import com.google.android.exoplayer2.util.ParsableByteArray;
 import com.google.android.exoplayer2.util.TimestampAdjuster;
-import com.google.android.exoplayer2.util.Util;
 import com.google.android.exoplayer2.video.ColorInfo;
+import com.google.common.base.Ascii;
 
 import java.io.EOFException;
 import java.io.IOException;
@@ -978,7 +978,7 @@
     @ParserName
     public static List<String> getParserNames(@NonNull MediaFormat mediaFormat) {
         String mimeType = mediaFormat.getString(MediaFormat.KEY_MIME);
-        mimeType = mimeType == null ? null : Util.toLowerInvariant(mimeType.trim());
+        mimeType = mimeType == null ? null : Ascii.toLowerCase(mimeType);
         if (TextUtils.isEmpty(mimeType)) {
             // No MIME type provided. Return all.
             return Collections.unmodifiableList(
@@ -1420,7 +1420,7 @@
         int flags = 0;
         TimestampAdjuster timestampAdjuster = null;
         if (mIgnoreTimestampOffset) {
-            timestampAdjuster = new TimestampAdjuster(TimestampAdjuster.DO_NOT_OFFSET);
+            timestampAdjuster = new TimestampAdjuster(TimestampAdjuster.MODE_NO_OFFSET);
         }
         switch (parserName) {
             case PARSER_NAME_MATROSKA:
diff --git a/api/Android.bp b/api/Android.bp
index 1ec1b3c..2e49a0c 100644
--- a/api/Android.bp
+++ b/api/Android.bp
@@ -97,6 +97,7 @@
         ":conscrypt.module.public.api{.public.api.txt}",
         ":framework-appsearch{.public.api.txt}",
         ":framework-connectivity{.public.api.txt}",
+        ":framework-connectivity-tiramisu{.public.api.txt}",
         ":framework-graphics{.public.api.txt}",
         ":framework-media{.public.api.txt}",
         ":framework-mediaprovider{.public.api.txt}",
@@ -123,10 +124,7 @@
             dest: "current.txt",
         },
         {
-            targets: [
-                "sdk",
-                "win_sdk",
-            ],
+            targets: ["sdk"],
             dir: "apistubs/android/public/api",
             dest: "android.txt",
         },
@@ -159,6 +157,7 @@
         ":conscrypt.module.public.api{.public.stubs.source}",
         ":framework-appsearch{.public.stubs.source}",
         ":framework-connectivity{.public.stubs.source}",
+        ":framework-connectivity-tiramisu{.public.stubs.source}",
         ":framework-graphics{.public.stubs.source}",
         ":framework-media{.public.stubs.source}",
         ":framework-mediaprovider{.public.stubs.source}",
@@ -188,6 +187,7 @@
         ":conscrypt.module.public.api{.public.removed-api.txt}",
         ":framework-appsearch{.public.removed-api.txt}",
         ":framework-connectivity{.public.removed-api.txt}",
+        ":framework-connectivity-tiramisu{.public.removed-api.txt}",
         ":framework-graphics{.public.removed-api.txt}",
         ":framework-media{.public.removed-api.txt}",
         ":framework-mediaprovider{.public.removed-api.txt}",
@@ -214,10 +214,7 @@
             dest: "removed.txt",
         },
         {
-            targets: [
-                "sdk",
-                "win_sdk",
-            ],
+            targets: ["sdk"],
             dir: "apistubs/android/public/api",
             dest: "removed.txt",
         },
@@ -231,6 +228,7 @@
         ":android.net.ipsec.ike{.system.api.txt}",
         ":framework-appsearch{.system.api.txt}",
         ":framework-connectivity{.system.api.txt}",
+        ":framework-connectivity-tiramisu{.system.api.txt}",
         ":framework-graphics{.system.api.txt}",
         ":framework-media{.system.api.txt}",
         ":framework-mediaprovider{.system.api.txt}",
@@ -256,10 +254,7 @@
             dest: "system-current.txt",
         },
         {
-            targets: [
-                "sdk",
-                "win_sdk",
-            ],
+            targets: ["sdk"],
             dir: "apistubs/android/system/api",
             dest: "android.txt",
         },
@@ -292,6 +287,7 @@
         ":android.net.ipsec.ike{.system.removed-api.txt}",
         ":framework-appsearch{.system.removed-api.txt}",
         ":framework-connectivity{.system.removed-api.txt}",
+        ":framework-connectivity-tiramisu{.system.removed-api.txt}",
         ":framework-graphics{.system.removed-api.txt}",
         ":framework-media{.system.removed-api.txt}",
         ":framework-mediaprovider{.system.removed-api.txt}",
@@ -317,10 +313,7 @@
             dest: "system-removed.txt",
         },
         {
-            targets: [
-                "sdk",
-                "win_sdk",
-            ],
+            targets: ["sdk"],
             dir: "apistubs/android/system/api",
             dest: "removed.txt",
         },
@@ -335,6 +328,7 @@
         ":android.net.ipsec.ike{.module-lib.api.txt}",
         ":framework-appsearch{.module-lib.api.txt}",
         ":framework-connectivity{.module-lib.api.txt}",
+        ":framework-connectivity-tiramisu{.module-lib.api.txt}",
         ":framework-graphics{.module-lib.api.txt}",
         ":framework-media{.module-lib.api.txt}",
         ":framework-mediaprovider{.module-lib.api.txt}",
@@ -360,10 +354,7 @@
             dest: "module-lib-current.txt",
         },
         {
-            targets: [
-                "sdk",
-                "win_sdk",
-            ],
+            targets: ["sdk"],
             dir: "apistubs/android/module-lib/api",
             dest: "android.txt",
         },
@@ -398,6 +389,7 @@
         ":android.net.ipsec.ike{.module-lib.removed-api.txt}",
         ":framework-appsearch{.module-lib.removed-api.txt}",
         ":framework-connectivity{.module-lib.removed-api.txt}",
+        ":framework-connectivity-tiramisu{.module-lib.removed-api.txt}",
         ":framework-graphics{.module-lib.removed-api.txt}",
         ":framework-media{.module-lib.removed-api.txt}",
         ":framework-mediaprovider{.module-lib.removed-api.txt}",
@@ -423,10 +415,7 @@
             dest: "module-lib-removed.txt",
         },
         {
-            targets: [
-                "sdk",
-                "win_sdk",
-            ],
+            targets: ["sdk"],
             dir: "apistubs/android/module-lib/api",
             dest: "removed.txt",
         },
@@ -467,10 +456,7 @@
             dest: "system-server-current.txt",
         },
         {
-            targets: [
-                "sdk",
-                "win_sdk",
-            ],
+            targets: ["sdk"],
             dir: "apistubs/android/system-server/api",
             dest: "android.txt",
         },
@@ -494,10 +480,7 @@
             dest: "system-server-removed.txt",
         },
         {
-            targets: [
-                "sdk",
-                "win_sdk",
-            ],
+            targets: ["sdk"],
             dir: "apistubs/android/system-server/api",
             dest: "removed.txt",
         },
@@ -519,6 +502,7 @@
         ":conscrypt.module.public.api.stubs{.jar}",
         ":framework-appsearch.stubs{.jar}",
         ":framework-connectivity.stubs{.jar}",
+        ":framework-connectivity-tiramisu.stubs{.jar}",
         ":framework-graphics.stubs{.jar}",
         ":framework-media.stubs{.jar}",
         ":framework-mediaprovider.stubs{.jar}",
@@ -538,9 +522,6 @@
     tools: ["api_versions_trimmer"],
     cmd: "$(location api_versions_trimmer) $(out) $(in)",
     dist: {
-        targets: [
-            "sdk",
-            "win_sdk",
-        ],
+        targets: ["sdk"],
     },
 }
diff --git a/boot/hiddenapi/hiddenapi-max-target-o.txt b/boot/hiddenapi/hiddenapi-max-target-o.txt
index 0ec918b..9153426 100644
--- a/boot/hiddenapi/hiddenapi-max-target-o.txt
+++ b/boot/hiddenapi/hiddenapi-max-target-o.txt
@@ -36441,93 +36441,6 @@
 Landroid/net/MobileLinkQualityInfo;->mLteSignalStrength:I
 Landroid/net/MobileLinkQualityInfo;->mMobileNetworkType:I
 Landroid/net/MobileLinkQualityInfo;->mRssi:I
-Landroid/net/nsd/DnsSdTxtRecord;-><init>()V
-Landroid/net/nsd/DnsSdTxtRecord;-><init>(Landroid/net/nsd/DnsSdTxtRecord;)V
-Landroid/net/nsd/DnsSdTxtRecord;-><init>([B)V
-Landroid/net/nsd/DnsSdTxtRecord;->contains(Ljava/lang/String;)Z
-Landroid/net/nsd/DnsSdTxtRecord;->CREATOR:Landroid/os/Parcelable$Creator;
-Landroid/net/nsd/DnsSdTxtRecord;->get(Ljava/lang/String;)Ljava/lang/String;
-Landroid/net/nsd/DnsSdTxtRecord;->getKey(I)Ljava/lang/String;
-Landroid/net/nsd/DnsSdTxtRecord;->getRawData()[B
-Landroid/net/nsd/DnsSdTxtRecord;->getValue(I)[B
-Landroid/net/nsd/DnsSdTxtRecord;->getValue(Ljava/lang/String;)[B
-Landroid/net/nsd/DnsSdTxtRecord;->getValueAsString(I)Ljava/lang/String;
-Landroid/net/nsd/DnsSdTxtRecord;->insert([B[BI)V
-Landroid/net/nsd/DnsSdTxtRecord;->keyCount()I
-Landroid/net/nsd/DnsSdTxtRecord;->mData:[B
-Landroid/net/nsd/DnsSdTxtRecord;->mSeperator:B
-Landroid/net/nsd/DnsSdTxtRecord;->remove(Ljava/lang/String;)I
-Landroid/net/nsd/DnsSdTxtRecord;->set(Ljava/lang/String;Ljava/lang/String;)V
-Landroid/net/nsd/DnsSdTxtRecord;->size()I
-Landroid/net/nsd/INsdManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
-Landroid/net/nsd/INsdManager$Stub$Proxy;->getInterfaceDescriptor()Ljava/lang/String;
-Landroid/net/nsd/INsdManager$Stub$Proxy;->getMessenger()Landroid/os/Messenger;
-Landroid/net/nsd/INsdManager$Stub$Proxy;->mRemote:Landroid/os/IBinder;
-Landroid/net/nsd/INsdManager$Stub$Proxy;->setEnabled(Z)V
-Landroid/net/nsd/INsdManager$Stub;-><init>()V
-Landroid/net/nsd/INsdManager$Stub;->DESCRIPTOR:Ljava/lang/String;
-Landroid/net/nsd/INsdManager$Stub;->TRANSACTION_getMessenger:I
-Landroid/net/nsd/INsdManager$Stub;->TRANSACTION_setEnabled:I
-Landroid/net/nsd/INsdManager;->setEnabled(Z)V
-Landroid/net/nsd/NsdManager;-><init>(Landroid/content/Context;Landroid/net/nsd/INsdManager;)V
-Landroid/net/nsd/NsdManager;->BASE:I
-Landroid/net/nsd/NsdManager;->checkListener(Ljava/lang/Object;)V
-Landroid/net/nsd/NsdManager;->checkProtocol(I)V
-Landroid/net/nsd/NsdManager;->checkServiceInfo(Landroid/net/nsd/NsdServiceInfo;)V
-Landroid/net/nsd/NsdManager;->DBG:Z
-Landroid/net/nsd/NsdManager;->DISABLE:I
-Landroid/net/nsd/NsdManager;->disconnect()V
-Landroid/net/nsd/NsdManager;->DISCOVER_SERVICES:I
-Landroid/net/nsd/NsdManager;->DISCOVER_SERVICES_FAILED:I
-Landroid/net/nsd/NsdManager;->DISCOVER_SERVICES_STARTED:I
-Landroid/net/nsd/NsdManager;->ENABLE:I
-Landroid/net/nsd/NsdManager;->EVENT_NAMES:Landroid/util/SparseArray;
-Landroid/net/nsd/NsdManager;->fatal(Ljava/lang/String;)V
-Landroid/net/nsd/NsdManager;->FIRST_LISTENER_KEY:I
-Landroid/net/nsd/NsdManager;->getListenerKey(Ljava/lang/Object;)I
-Landroid/net/nsd/NsdManager;->getMessenger()Landroid/os/Messenger;
-Landroid/net/nsd/NsdManager;->getNsdServiceInfoType(Landroid/net/nsd/NsdServiceInfo;)Ljava/lang/String;
-Landroid/net/nsd/NsdManager;->init()V
-Landroid/net/nsd/NsdManager;->mAsyncChannel:Lcom/android/internal/util/AsyncChannel;
-Landroid/net/nsd/NsdManager;->mConnected:Ljava/util/concurrent/CountDownLatch;
-Landroid/net/nsd/NsdManager;->mContext:Landroid/content/Context;
-Landroid/net/nsd/NsdManager;->mHandler:Landroid/net/nsd/NsdManager$ServiceHandler;
-Landroid/net/nsd/NsdManager;->mListenerKey:I
-Landroid/net/nsd/NsdManager;->mListenerMap:Landroid/util/SparseArray;
-Landroid/net/nsd/NsdManager;->mMapLock:Ljava/lang/Object;
-Landroid/net/nsd/NsdManager;->mService:Landroid/net/nsd/INsdManager;
-Landroid/net/nsd/NsdManager;->mServiceMap:Landroid/util/SparseArray;
-Landroid/net/nsd/NsdManager;->nameOf(I)Ljava/lang/String;
-Landroid/net/nsd/NsdManager;->NATIVE_DAEMON_EVENT:I
-Landroid/net/nsd/NsdManager;->nextListenerKey()I
-Landroid/net/nsd/NsdManager;->putListener(Ljava/lang/Object;Landroid/net/nsd/NsdServiceInfo;)I
-Landroid/net/nsd/NsdManager;->REGISTER_SERVICE:I
-Landroid/net/nsd/NsdManager;->REGISTER_SERVICE_FAILED:I
-Landroid/net/nsd/NsdManager;->REGISTER_SERVICE_SUCCEEDED:I
-Landroid/net/nsd/NsdManager;->removeListener(I)V
-Landroid/net/nsd/NsdManager;->RESOLVE_SERVICE:I
-Landroid/net/nsd/NsdManager;->RESOLVE_SERVICE_FAILED:I
-Landroid/net/nsd/NsdManager;->RESOLVE_SERVICE_SUCCEEDED:I
-Landroid/net/nsd/NsdManager;->SERVICE_FOUND:I
-Landroid/net/nsd/NsdManager;->SERVICE_LOST:I
-Landroid/net/nsd/NsdManager;->setEnabled(Z)V
-Landroid/net/nsd/NsdManager;->STOP_DISCOVERY:I
-Landroid/net/nsd/NsdManager;->STOP_DISCOVERY_FAILED:I
-Landroid/net/nsd/NsdManager;->STOP_DISCOVERY_SUCCEEDED:I
-Landroid/net/nsd/NsdManager;->TAG:Ljava/lang/String;
-Landroid/net/nsd/NsdManager;->UNREGISTER_SERVICE:I
-Landroid/net/nsd/NsdManager;->UNREGISTER_SERVICE_FAILED:I
-Landroid/net/nsd/NsdManager;->UNREGISTER_SERVICE_SUCCEEDED:I
-Landroid/net/nsd/NsdServiceInfo;-><init>(Ljava/lang/String;Ljava/lang/String;)V
-Landroid/net/nsd/NsdServiceInfo;->getTxtRecord()[B
-Landroid/net/nsd/NsdServiceInfo;->getTxtRecordSize()I
-Landroid/net/nsd/NsdServiceInfo;->mHost:Ljava/net/InetAddress;
-Landroid/net/nsd/NsdServiceInfo;->mPort:I
-Landroid/net/nsd/NsdServiceInfo;->mServiceName:Ljava/lang/String;
-Landroid/net/nsd/NsdServiceInfo;->mServiceType:Ljava/lang/String;
-Landroid/net/nsd/NsdServiceInfo;->mTxtRecord:Landroid/util/ArrayMap;
-Landroid/net/nsd/NsdServiceInfo;->setTxtRecords(Ljava/lang/String;)V
-Landroid/net/nsd/NsdServiceInfo;->TAG:Ljava/lang/String;
 Landroid/net/PacProxySelector;-><init>()V
 Landroid/net/PacProxySelector;->mDefaultList:Ljava/util/List;
 Landroid/net/PacProxySelector;->mProxyService:Lcom/android/net/IProxyService;
diff --git a/boot/hiddenapi/hiddenapi-max-target-r-loprio.txt b/boot/hiddenapi/hiddenapi-max-target-r-loprio.txt
index 79d2521..20d7cc0 100644
--- a/boot/hiddenapi/hiddenapi-max-target-r-loprio.txt
+++ b/boot/hiddenapi/hiddenapi-max-target-r-loprio.txt
@@ -21,7 +21,6 @@
 Landroid/Manifest$permission;->READ_FRAME_BUFFER:Ljava/lang/String;
 Landroid/media/IVolumeController$Stub;->asInterface(Landroid/os/IBinder;)Landroid/media/IVolumeController;
 Landroid/net/INetworkPolicyListener$Stub;-><init>()V
-Landroid/net/nsd/INsdManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/nsd/INsdManager;
 Landroid/net/sip/ISipSession$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/sip/ISipSession;
 Landroid/nfc/INfcAdapter$Stub;->TRANSACTION_enable:I
 Landroid/os/IPowerManager$Stub;->TRANSACTION_acquireWakeLock:I
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 05a06619..1f4a64f 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -81,18 +81,18 @@
 static constexpr const char* OEM_USERSPACE_REBOOT_ANIMATION_FILE = "/oem/media/userspace-reboot.zip";
 static constexpr const char* SYSTEM_USERSPACE_REBOOT_ANIMATION_FILE = "/system/media/userspace-reboot.zip";
 
-static const char SYSTEM_DATA_DIR_PATH[] = "/data/system";
-static const char SYSTEM_TIME_DIR_NAME[] = "time";
-static const char SYSTEM_TIME_DIR_PATH[] = "/data/system/time";
+static const char BOOTANIM_DATA_DIR_PATH[] = "/data/bootanim";
+static const char BOOTANIM_TIME_DIR_NAME[] = "time";
+static const char BOOTANIM_TIME_DIR_PATH[] = "/data/bootanim/time";
 static const char CLOCK_FONT_ASSET[] = "images/clock_font.png";
 static const char CLOCK_FONT_ZIP_NAME[] = "clock_font.png";
 static const char PROGRESS_FONT_ASSET[] = "images/progress_font.png";
 static const char PROGRESS_FONT_ZIP_NAME[] = "progress_font.png";
 static const char LAST_TIME_CHANGED_FILE_NAME[] = "last_time_change";
-static const char LAST_TIME_CHANGED_FILE_PATH[] = "/data/system/time/last_time_change";
+static const char LAST_TIME_CHANGED_FILE_PATH[] = "/data/bootanim/time/last_time_change";
 static const char ACCURATE_TIME_FLAG_FILE_NAME[] = "time_is_accurate";
-static const char ACCURATE_TIME_FLAG_FILE_PATH[] = "/data/system/time/time_is_accurate";
-static const char TIME_FORMAT_12_HOUR_FLAG_FILE_PATH[] = "/data/system/time/time_format_12_hour";
+static const char ACCURATE_TIME_FLAG_FILE_PATH[] = "/data/bootanim/time/time_is_accurate";
+static const char TIME_FORMAT_12_HOUR_FLAG_FILE_PATH[] = "/data/bootanim/time/time_format_12_hour";
 // Java timestamp format. Don't show the clock if the date is before 2000-01-01 00:00:00.
 static const long long ACCURATE_TIME_EPOCH = 946684800000;
 static constexpr char FONT_BEGIN_CHAR = ' ';
@@ -1741,7 +1741,7 @@
 }
 
 BootAnimation::TimeCheckThread::TimeCheckThread(BootAnimation* bootAnimation) : Thread(false),
-    mInotifyFd(-1), mSystemWd(-1), mTimeWd(-1), mBootAnimation(bootAnimation) {}
+    mInotifyFd(-1), mBootAnimWd(-1), mTimeWd(-1), mBootAnimation(bootAnimation) {}
 
 BootAnimation::TimeCheckThread::~TimeCheckThread() {
     // mInotifyFd may be -1 but that's ok since we're not at risk of attempting to close a valid FD.
@@ -1784,7 +1784,7 @@
     const struct inotify_event *event;
     for (char* ptr = buff; ptr < buff + length; ptr += sizeof(struct inotify_event) + event->len) {
         event = (const struct inotify_event *) ptr;
-        if (event->wd == mSystemWd && strcmp(SYSTEM_TIME_DIR_NAME, event->name) == 0) {
+        if (event->wd == mBootAnimWd && strcmp(BOOTANIM_TIME_DIR_NAME, event->name) == 0) {
             addTimeDirWatch();
         } else if (event->wd == mTimeWd && (strcmp(LAST_TIME_CHANGED_FILE_NAME, event->name) == 0
                 || strcmp(ACCURATE_TIME_FLAG_FILE_NAME, event->name) == 0)) {
@@ -1796,12 +1796,12 @@
 }
 
 void BootAnimation::TimeCheckThread::addTimeDirWatch() {
-        mTimeWd = inotify_add_watch(mInotifyFd, SYSTEM_TIME_DIR_PATH,
+        mTimeWd = inotify_add_watch(mInotifyFd, BOOTANIM_TIME_DIR_PATH,
                 IN_CLOSE_WRITE | IN_MOVED_TO | IN_ATTRIB);
         if (mTimeWd > 0) {
             // No need to watch for the time directory to be created if it already exists
-            inotify_rm_watch(mInotifyFd, mSystemWd);
-            mSystemWd = -1;
+            inotify_rm_watch(mInotifyFd, mBootAnimWd);
+            mBootAnimWd = -1;
         }
 }
 
@@ -1812,11 +1812,11 @@
         return NO_INIT;
     }
 
-    mSystemWd = inotify_add_watch(mInotifyFd, SYSTEM_DATA_DIR_PATH, IN_CREATE | IN_ATTRIB);
-    if (mSystemWd < 0) {
+    mBootAnimWd = inotify_add_watch(mInotifyFd, BOOTANIM_DATA_DIR_PATH, IN_CREATE | IN_ATTRIB);
+    if (mBootAnimWd < 0) {
         close(mInotifyFd);
         mInotifyFd = -1;
-        SLOGE("Could not add watch for %s: %s", SYSTEM_DATA_DIR_PATH, strerror(errno));
+        SLOGE("Could not add watch for %s: %s", BOOTANIM_DATA_DIR_PATH, strerror(errno));
         return NO_INIT;
     }
 
diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h
index 7a597da..4c378cb 100644
--- a/cmds/bootanimation/BootAnimation.h
+++ b/cmds/bootanimation/BootAnimation.h
@@ -161,7 +161,7 @@
         void                addTimeDirWatch();
 
         int mInotifyFd;
-        int mSystemWd;
+        int mBootAnimWd;
         int mTimeWd;
         BootAnimation* mBootAnimation;
     };
diff --git a/core/api/current.txt b/core/api/current.txt
index b52a3e4..70c09a8 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -61,6 +61,7 @@
     field public static final String BLUETOOTH_PRIVILEGED = "android.permission.BLUETOOTH_PRIVILEGED";
     field public static final String BLUETOOTH_SCAN = "android.permission.BLUETOOTH_SCAN";
     field public static final String BODY_SENSORS = "android.permission.BODY_SENSORS";
+    field public static final String BODY_SENSORS_BACKGROUND = "android.permission.BODY_SENSORS_BACKGROUND";
     field public static final String BROADCAST_PACKAGE_REMOVED = "android.permission.BROADCAST_PACKAGE_REMOVED";
     field public static final String BROADCAST_SMS = "android.permission.BROADCAST_SMS";
     field public static final String BROADCAST_STICKY = "android.permission.BROADCAST_STICKY";
@@ -2257,6 +2258,7 @@
     field public static final int TextAppearance = 16973886; // 0x103003e
     field public static final int TextAppearance_DeviceDefault = 16974253; // 0x10301ad
     field public static final int TextAppearance_DeviceDefault_DialogWindowTitle = 16974264; // 0x10301b8
+    field public static final int TextAppearance_DeviceDefault_Headline;
     field public static final int TextAppearance_DeviceDefault_Inverse = 16974254; // 0x10301ae
     field public static final int TextAppearance_DeviceDefault_Large = 16974255; // 0x10301af
     field public static final int TextAppearance_DeviceDefault_Large_Inverse = 16974256; // 0x10301b0
@@ -3013,6 +3015,8 @@
 
   public abstract class AccessibilityService extends android.app.Service {
     ctor public AccessibilityService();
+    method public boolean clearCache();
+    method public boolean clearCachedSubtree(@NonNull android.view.accessibility.AccessibilityNodeInfo);
     method public final void disableSelf();
     method public final boolean dispatchGesture(@NonNull android.accessibilityservice.GestureDescription, @Nullable android.accessibilityservice.AccessibilityService.GestureResultCallback, @Nullable android.os.Handler);
     method public android.view.accessibility.AccessibilityNodeInfo findFocus(int);
@@ -3027,6 +3031,8 @@
     method @NonNull public final android.accessibilityservice.TouchInteractionController getTouchInteractionController(int);
     method public java.util.List<android.view.accessibility.AccessibilityWindowInfo> getWindows();
     method @NonNull public final android.util.SparseArray<java.util.List<android.view.accessibility.AccessibilityWindowInfo>> getWindowsOnAllDisplays();
+    method public boolean isCacheEnabled();
+    method public boolean isNodeInCache(@NonNull android.view.accessibility.AccessibilityNodeInfo);
     method public abstract void onAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
     method public final android.os.IBinder onBind(android.content.Intent);
     method @Deprecated protected boolean onGesture(int);
@@ -3037,6 +3043,7 @@
     method public void onSystemActionsChanged();
     method public final boolean performGlobalAction(int);
     method public void setAccessibilityFocusAppearance(int, @ColorInt int);
+    method public boolean setCacheEnabled(boolean);
     method public void setGestureDetectionPassthroughRegion(int, @NonNull android.graphics.Region);
     method public final void setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo);
     method public void setTouchExplorationPassthroughRegion(int, @NonNull android.graphics.Region);
@@ -4463,6 +4470,7 @@
     method public android.app.ActivityOptions setLaunchDisplayId(int);
     method public android.app.ActivityOptions setLockTaskEnabled(boolean);
     method public void setPendingIntentBackgroundActivityLaunchAllowed(boolean);
+    method @NonNull public android.app.ActivityOptions setSplashScreenStyle(int);
     method public android.os.Bundle toBundle();
     method public void update(android.app.ActivityOptions);
     field public static final String EXTRA_USAGE_TIME_REPORT = "android.activity.usage_time";
@@ -16524,6 +16532,7 @@
     method @NonNull public static android.graphics.RenderEffect createColorFilterEffect(@NonNull android.graphics.ColorFilter);
     method @NonNull public static android.graphics.RenderEffect createOffsetEffect(float, float);
     method @NonNull public static android.graphics.RenderEffect createOffsetEffect(float, float, @NonNull android.graphics.RenderEffect);
+    method @NonNull public static android.graphics.RenderEffect createRuntimeShaderEffect(@NonNull android.graphics.RuntimeShader, @NonNull String);
     method @NonNull public static android.graphics.RenderEffect createShaderEffect(@NonNull android.graphics.Shader);
   }
 
@@ -20244,6 +20253,7 @@
 
   public final class GnssMeasurementRequest implements android.os.Parcelable {
     method public int describeContents();
+    method @IntRange(from=0) public int getIntervalMillis();
     method public boolean isFullTracking();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssMeasurementRequest> CREATOR;
@@ -20254,6 +20264,7 @@
     ctor public GnssMeasurementRequest.Builder(@NonNull android.location.GnssMeasurementRequest);
     method @NonNull public android.location.GnssMeasurementRequest build();
     method @NonNull public android.location.GnssMeasurementRequest.Builder setFullTracking(boolean);
+    method @NonNull public android.location.GnssMeasurementRequest.Builder setIntervalMillis(@IntRange(from=0) int);
   }
 
   public final class GnssMeasurementsEvent implements android.os.Parcelable {
@@ -20939,11 +20950,12 @@
     method @NonNull public java.util.List<android.media.AudioDeviceInfo> getAvailableCommunicationDevices();
     method @Nullable public android.media.AudioDeviceInfo getCommunicationDevice();
     method public android.media.AudioDeviceInfo[] getDevices(int);
+    method public static int getDirectPlaybackSupport(@NonNull android.media.AudioFormat, @NonNull android.media.AudioAttributes);
     method public int getEncodedSurroundMode();
     method public java.util.List<android.media.MicrophoneInfo> getMicrophones() throws java.io.IOException;
     method public int getMode();
     method public String getParameters(String);
-    method public static int getPlaybackOffloadSupport(@NonNull android.media.AudioFormat, @NonNull android.media.AudioAttributes);
+    method @Deprecated public static int getPlaybackOffloadSupport(@NonNull android.media.AudioFormat, @NonNull android.media.AudioAttributes);
     method public String getProperty(String);
     method public int getRingerMode();
     method @Deprecated public int getRouting(int);
@@ -21034,6 +21046,10 @@
     field public static final int AUDIOFOCUS_REQUEST_FAILED = 0; // 0x0
     field public static final int AUDIOFOCUS_REQUEST_GRANTED = 1; // 0x1
     field public static final int AUDIO_SESSION_ID_GENERATE = 0; // 0x0
+    field public static final int DIRECT_PLAYBACK_BITSTREAM_SUPPORTED = 4; // 0x4
+    field public static final int DIRECT_PLAYBACK_NOT_SUPPORTED = 0; // 0x0
+    field public static final int DIRECT_PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED = 3; // 0x3
+    field public static final int DIRECT_PLAYBACK_OFFLOAD_SUPPORTED = 1; // 0x1
     field public static final int ENCODED_SURROUND_OUTPUT_ALWAYS = 2; // 0x2
     field public static final int ENCODED_SURROUND_OUTPUT_AUTO = 0; // 0x0
     field public static final int ENCODED_SURROUND_OUTPUT_MANUAL = 3; // 0x3
@@ -21424,7 +21440,7 @@
     method public int getStreamType();
     method public boolean getTimestamp(android.media.AudioTimestamp);
     method public int getUnderrunCount();
-    method public static boolean isDirectPlaybackSupported(@NonNull android.media.AudioFormat, @NonNull android.media.AudioAttributes);
+    method @Deprecated public static boolean isDirectPlaybackSupported(@NonNull android.media.AudioFormat, @NonNull android.media.AudioAttributes);
     method public boolean isOffloadedPlayback();
     method public void pause() throws java.lang.IllegalStateException;
     method public void play() throws java.lang.IllegalStateException;
@@ -21932,6 +21948,7 @@
   public class MediaActionSound {
     ctor public MediaActionSound();
     method public void load(int);
+    method public static boolean mustPlayShutterSound();
     method public void play(int);
     method public void release();
     field public static final int FOCUS_COMPLETE = 1; // 0x1
@@ -27424,65 +27441,6 @@
 
 }
 
-package android.net.nsd {
-
-  public final class NsdManager {
-    method public void discoverServices(String, int, android.net.nsd.NsdManager.DiscoveryListener);
-    method public void registerService(android.net.nsd.NsdServiceInfo, int, android.net.nsd.NsdManager.RegistrationListener);
-    method public void resolveService(android.net.nsd.NsdServiceInfo, android.net.nsd.NsdManager.ResolveListener);
-    method public void stopServiceDiscovery(android.net.nsd.NsdManager.DiscoveryListener);
-    method public void unregisterService(android.net.nsd.NsdManager.RegistrationListener);
-    field public static final String ACTION_NSD_STATE_CHANGED = "android.net.nsd.STATE_CHANGED";
-    field public static final String EXTRA_NSD_STATE = "nsd_state";
-    field public static final int FAILURE_ALREADY_ACTIVE = 3; // 0x3
-    field public static final int FAILURE_INTERNAL_ERROR = 0; // 0x0
-    field public static final int FAILURE_MAX_LIMIT = 4; // 0x4
-    field public static final int NSD_STATE_DISABLED = 1; // 0x1
-    field public static final int NSD_STATE_ENABLED = 2; // 0x2
-    field public static final int PROTOCOL_DNS_SD = 1; // 0x1
-  }
-
-  public static interface NsdManager.DiscoveryListener {
-    method public void onDiscoveryStarted(String);
-    method public void onDiscoveryStopped(String);
-    method public void onServiceFound(android.net.nsd.NsdServiceInfo);
-    method public void onServiceLost(android.net.nsd.NsdServiceInfo);
-    method public void onStartDiscoveryFailed(String, int);
-    method public void onStopDiscoveryFailed(String, int);
-  }
-
-  public static interface NsdManager.RegistrationListener {
-    method public void onRegistrationFailed(android.net.nsd.NsdServiceInfo, int);
-    method public void onServiceRegistered(android.net.nsd.NsdServiceInfo);
-    method public void onServiceUnregistered(android.net.nsd.NsdServiceInfo);
-    method public void onUnregistrationFailed(android.net.nsd.NsdServiceInfo, int);
-  }
-
-  public static interface NsdManager.ResolveListener {
-    method public void onResolveFailed(android.net.nsd.NsdServiceInfo, int);
-    method public void onServiceResolved(android.net.nsd.NsdServiceInfo);
-  }
-
-  public final class NsdServiceInfo implements android.os.Parcelable {
-    ctor public NsdServiceInfo();
-    method public int describeContents();
-    method public java.util.Map<java.lang.String,byte[]> getAttributes();
-    method public java.net.InetAddress getHost();
-    method public int getPort();
-    method public String getServiceName();
-    method public String getServiceType();
-    method public void removeAttribute(String);
-    method public void setAttribute(String, String);
-    method public void setHost(java.net.InetAddress);
-    method public void setPort(int);
-    method public void setServiceName(String);
-    method public void setServiceType(String);
-    method public void writeToParcel(android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.net.nsd.NsdServiceInfo> CREATOR;
-  }
-
-}
-
 package android.net.rtp {
 
   @Deprecated public class AudioCodec {
@@ -32528,6 +32486,7 @@
 
   public final class SystemClock {
     method @NonNull public static java.time.Clock currentGnssTimeClock();
+    method @NonNull public static java.time.Clock currentNetworkTimeClock();
     method public static long currentThreadTimeMillis();
     method public static long elapsedRealtime();
     method public static long elapsedRealtimeNanos();
@@ -34334,6 +34293,7 @@
     field public static final int PRESENTATION_ALLOWED = 1; // 0x1
     field public static final int PRESENTATION_PAYPHONE = 4; // 0x4
     field public static final int PRESENTATION_RESTRICTED = 2; // 0x2
+    field public static final int PRESENTATION_UNAVAILABLE = 5; // 0x5
     field public static final int PRESENTATION_UNKNOWN = 3; // 0x3
     field public static final String PRIORITY = "priority";
     field public static final int PRIORITY_NORMAL = 0; // 0x0
@@ -35763,6 +35723,7 @@
     field public static final String ACTION_APPLICATION_DETAILS_SETTINGS = "android.settings.APPLICATION_DETAILS_SETTINGS";
     field public static final String ACTION_APPLICATION_DEVELOPMENT_SETTINGS = "android.settings.APPLICATION_DEVELOPMENT_SETTINGS";
     field public static final String ACTION_APPLICATION_SETTINGS = "android.settings.APPLICATION_SETTINGS";
+    field public static final String ACTION_APP_LOCALE_SETTINGS = "android.settings.APP_LOCALE_SETTINGS";
     field public static final String ACTION_APP_NOTIFICATION_BUBBLE_SETTINGS = "android.settings.APP_NOTIFICATION_BUBBLE_SETTINGS";
     field public static final String ACTION_APP_NOTIFICATION_SETTINGS = "android.settings.APP_NOTIFICATION_SETTINGS";
     field public static final String ACTION_APP_OPEN_BY_DEFAULT_SETTINGS = "android.settings.APP_OPEN_BY_DEFAULT_SETTINGS";
@@ -41106,6 +41067,7 @@
     field public static final int PRESENTATION_ALLOWED = 1; // 0x1
     field public static final int PRESENTATION_PAYPHONE = 4; // 0x4
     field public static final int PRESENTATION_RESTRICTED = 2; // 0x2
+    field public static final int PRESENTATION_UNAVAILABLE = 5; // 0x5
     field public static final int PRESENTATION_UNKNOWN = 3; // 0x3
     field public static final int PRIORITY_NORMAL = 0; // 0x0
     field public static final int PRIORITY_URGENT = 1; // 0x1
@@ -41524,6 +41486,7 @@
     field public static final String KEY_EDITABLE_WFC_ROAMING_MODE_BOOL = "editable_wfc_roaming_mode_bool";
     field public static final String KEY_EMERGENCY_NOTIFICATION_DELAY_INT = "emergency_notification_delay_int";
     field public static final String KEY_EMERGENCY_NUMBER_PREFIX_STRING_ARRAY = "emergency_number_prefix_string_array";
+    field public static final String KEY_ENABLE_CROSS_SIM_CALLING_ON_OPPORTUNISTIC_DATA_BOOL = "enable_cross_sim_calling_on_opportunistic_data_bool";
     field public static final String KEY_ENABLE_DIALER_KEY_VIBRATION_BOOL = "enable_dialer_key_vibration_bool";
     field public static final String KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL = "enhanced_4g_lte_on_by_default_bool";
     field public static final String KEY_ENHANCED_4G_LTE_TITLE_VARIANT_INT = "enhanced_4g_lte_title_variant_int";
@@ -43504,9 +43467,12 @@
     field public static final int DATA_DISCONNECTED = 0; // 0x0
     field public static final int DATA_DISCONNECTING = 4; // 0x4
     field public static final int DATA_ENABLED_REASON_CARRIER = 2; // 0x2
+    field public static final int DATA_ENABLED_REASON_OVERRIDE = 4; // 0x4
     field public static final int DATA_ENABLED_REASON_POLICY = 1; // 0x1
     field public static final int DATA_ENABLED_REASON_THERMAL = 3; // 0x3
+    field public static final int DATA_ENABLED_REASON_UNKNOWN = -1; // 0xffffffff
     field public static final int DATA_ENABLED_REASON_USER = 0; // 0x0
+    field public static final int DATA_HANDOVER_IN_PROGRESS = 5; // 0x5
     field public static final int DATA_SUSPENDED = 3; // 0x3
     field public static final int DATA_UNKNOWN = -1; // 0xffffffff
     field public static final int DEFAULT_PORT_INDEX = 0; // 0x0
@@ -43756,6 +43722,8 @@
     method public String getMmsProxyAddressAsString();
     method public int getMmsProxyPort();
     method public android.net.Uri getMmsc();
+    method public int getMtuV4();
+    method public int getMtuV6();
     method public int getMvnoType();
     method public int getNetworkTypeBitmask();
     method public String getOperatorNumeric();
@@ -43812,10 +43780,14 @@
     method @NonNull public android.telephony.data.ApnSetting.Builder setMmsProxyAddress(@Nullable String);
     method @NonNull public android.telephony.data.ApnSetting.Builder setMmsProxyPort(int);
     method @NonNull public android.telephony.data.ApnSetting.Builder setMmsc(@Nullable android.net.Uri);
+    method @NonNull public android.telephony.data.ApnSetting.Builder setMtuV4(int);
+    method @NonNull public android.telephony.data.ApnSetting.Builder setMtuV6(int);
     method @NonNull public android.telephony.data.ApnSetting.Builder setMvnoType(int);
     method @NonNull public android.telephony.data.ApnSetting.Builder setNetworkTypeBitmask(int);
     method @NonNull public android.telephony.data.ApnSetting.Builder setOperatorNumeric(@Nullable String);
     method @NonNull public android.telephony.data.ApnSetting.Builder setPassword(@Nullable String);
+    method @NonNull public android.telephony.data.ApnSetting.Builder setPersistent(boolean);
+    method @NonNull public android.telephony.data.ApnSetting.Builder setProfileId(int);
     method @NonNull public android.telephony.data.ApnSetting.Builder setProtocol(int);
     method @Deprecated public android.telephony.data.ApnSetting.Builder setProxyAddress(java.net.InetAddress);
     method @NonNull public android.telephony.data.ApnSetting.Builder setProxyAddress(@Nullable String);
@@ -43981,7 +43953,7 @@
     method public boolean isSimPortAvailable(int);
     method public void startResolutionActivity(android.app.Activity, int, android.content.Intent, android.app.PendingIntent) throws android.content.IntentSender.SendIntentException;
     method @Deprecated @RequiresPermission("android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS") public void switchToSubscription(int, android.app.PendingIntent);
-    method @RequiresPermission("android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS") public void switchToSubscription(int, int, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.euicc.EuiccManager.ResultListener);
+    method @RequiresPermission("android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS") public void switchToSubscription(int, int, @NonNull android.app.PendingIntent);
     method @RequiresPermission("android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS") public void updateSubscriptionNickname(int, @Nullable String, @NonNull android.app.PendingIntent);
     field public static final String ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS = "android.telephony.euicc.action.MANAGE_EMBEDDED_SUBSCRIPTIONS";
     field public static final String ACTION_NOTIFY_CARRIER_SETUP_INCOMPLETE = "android.telephony.euicc.action.NOTIFY_CARRIER_SETUP_INCOMPLETE";
@@ -44027,10 +43999,6 @@
     field public static final int OPERATION_SYSTEM = 1; // 0x1
   }
 
-  public static interface EuiccManager.ResultListener {
-    method public void onComplete(int, @Nullable android.content.Intent);
-  }
-
 }
 
 package android.telephony.gsm {
@@ -51427,9 +51395,9 @@
     method public int getRecordCount();
     method public int getWindowChanges();
     method public void initFromParcel(android.os.Parcel);
-    method public static android.view.accessibility.AccessibilityEvent obtain(int);
-    method public static android.view.accessibility.AccessibilityEvent obtain(android.view.accessibility.AccessibilityEvent);
-    method public static android.view.accessibility.AccessibilityEvent obtain();
+    method @Deprecated public static android.view.accessibility.AccessibilityEvent obtain(int);
+    method @Deprecated public static android.view.accessibility.AccessibilityEvent obtain(android.view.accessibility.AccessibilityEvent);
+    method @Deprecated public static android.view.accessibility.AccessibilityEvent obtain();
     method public void setAction(int);
     method public void setContentChangeTypes(int);
     method public void setEventTime(long);
@@ -51617,13 +51585,13 @@
     method public boolean isShowingHintText();
     method public boolean isTextEntryKey();
     method public boolean isVisibleToUser();
-    method public static android.view.accessibility.AccessibilityNodeInfo obtain(android.view.View);
-    method public static android.view.accessibility.AccessibilityNodeInfo obtain(android.view.View, int);
-    method public static android.view.accessibility.AccessibilityNodeInfo obtain();
-    method public static android.view.accessibility.AccessibilityNodeInfo obtain(android.view.accessibility.AccessibilityNodeInfo);
+    method @Deprecated public static android.view.accessibility.AccessibilityNodeInfo obtain(android.view.View);
+    method @Deprecated public static android.view.accessibility.AccessibilityNodeInfo obtain(android.view.View, int);
+    method @Deprecated public static android.view.accessibility.AccessibilityNodeInfo obtain();
+    method @Deprecated public static android.view.accessibility.AccessibilityNodeInfo obtain(android.view.accessibility.AccessibilityNodeInfo);
     method public boolean performAction(int);
     method public boolean performAction(int, android.os.Bundle);
-    method public void recycle();
+    method @Deprecated public void recycle();
     method public boolean refresh();
     method public boolean refreshWithExtraData(String, android.os.Bundle);
     method @Deprecated public void removeAction(int);
@@ -51802,8 +51770,8 @@
     method public int getRowCount();
     method public int getSelectionMode();
     method public boolean isHierarchical();
-    method public static android.view.accessibility.AccessibilityNodeInfo.CollectionInfo obtain(int, int, boolean);
-    method public static android.view.accessibility.AccessibilityNodeInfo.CollectionInfo obtain(int, int, boolean, int);
+    method @Deprecated public static android.view.accessibility.AccessibilityNodeInfo.CollectionInfo obtain(int, int, boolean);
+    method @Deprecated public static android.view.accessibility.AccessibilityNodeInfo.CollectionInfo obtain(int, int, boolean, int);
     field public static final int SELECTION_MODE_MULTIPLE = 2; // 0x2
     field public static final int SELECTION_MODE_NONE = 0; // 0x0
     field public static final int SELECTION_MODE_SINGLE = 1; // 0x1
@@ -51820,9 +51788,9 @@
     method @Nullable public String getRowTitle();
     method @Deprecated public boolean isHeading();
     method public boolean isSelected();
-    method public static android.view.accessibility.AccessibilityNodeInfo.CollectionItemInfo obtain(int, int, int, int, boolean);
-    method public static android.view.accessibility.AccessibilityNodeInfo.CollectionItemInfo obtain(int, int, int, int, boolean, boolean);
-    method @NonNull public static android.view.accessibility.AccessibilityNodeInfo.CollectionItemInfo obtain(@Nullable String, int, int, @Nullable String, int, int, boolean, boolean);
+    method @Deprecated public static android.view.accessibility.AccessibilityNodeInfo.CollectionItemInfo obtain(int, int, int, int, boolean);
+    method @Deprecated public static android.view.accessibility.AccessibilityNodeInfo.CollectionItemInfo obtain(int, int, int, int, boolean, boolean);
+    method @Deprecated @NonNull public static android.view.accessibility.AccessibilityNodeInfo.CollectionItemInfo obtain(@Nullable String, int, int, @Nullable String, int, int, boolean, boolean);
   }
 
   public static final class AccessibilityNodeInfo.CollectionItemInfo.Builder {
@@ -51850,7 +51818,7 @@
     method public float getMax();
     method public float getMin();
     method public int getType();
-    method public static android.view.accessibility.AccessibilityNodeInfo.RangeInfo obtain(int, float, float, float);
+    method @Deprecated public static android.view.accessibility.AccessibilityNodeInfo.RangeInfo obtain(int, float, float, float);
     field public static final int RANGE_TYPE_FLOAT = 1; // 0x1
     field public static final int RANGE_TYPE_INT = 0; // 0x0
     field public static final int RANGE_TYPE_PERCENT = 2; // 0x2
@@ -51904,9 +51872,9 @@
     method public boolean isFullScreen();
     method public boolean isPassword();
     method public boolean isScrollable();
-    method public static android.view.accessibility.AccessibilityRecord obtain(android.view.accessibility.AccessibilityRecord);
-    method public static android.view.accessibility.AccessibilityRecord obtain();
-    method public void recycle();
+    method @Deprecated public static android.view.accessibility.AccessibilityRecord obtain(android.view.accessibility.AccessibilityRecord);
+    method @Deprecated public static android.view.accessibility.AccessibilityRecord obtain();
+    method @Deprecated public void recycle();
     method public void setAddedCount(int);
     method public void setBeforeText(CharSequence);
     method public void setChecked(boolean);
@@ -53004,11 +52972,11 @@
     field @NonNull public static final android.os.Parcelable.Creator<android.view.inputmethod.TextAttribute> CREATOR;
   }
 
-  public static final class TextAttribute.TextAttributeBuilder {
-    ctor public TextAttribute.TextAttributeBuilder();
+  public static final class TextAttribute.Builder {
+    ctor public TextAttribute.Builder();
     method @NonNull public android.view.inputmethod.TextAttribute build();
-    method @NonNull public android.view.inputmethod.TextAttribute.TextAttributeBuilder setExtras(@NonNull android.os.PersistableBundle);
-    method @NonNull public android.view.inputmethod.TextAttribute.TextAttributeBuilder setTextConversionSuggestions(@NonNull java.util.List<java.lang.String>);
+    method @NonNull public android.view.inputmethod.TextAttribute.Builder setExtras(@NonNull android.os.PersistableBundle);
+    method @NonNull public android.view.inputmethod.TextAttribute.Builder setTextConversionSuggestions(@NonNull java.util.List<java.lang.String>);
   }
 
   public final class TextSnapshot {
@@ -57710,6 +57678,8 @@
     method public void clearOnExitAnimationListener();
     method public void setOnExitAnimationListener(@NonNull android.window.SplashScreen.OnExitAnimationListener);
     method public void setSplashScreenTheme(@StyleRes int);
+    field public static final int SPLASH_SCREEN_STYLE_EMPTY = 0; // 0x0
+    field public static final int SPLASH_SCREEN_STYLE_ICON = 1; // 0x1
   }
 
   public static interface SplashScreen.OnExitAnimationListener {
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index a51d2b1..53bc8a6 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -24,8 +24,8 @@
   }
 
   public class BroadcastOptions {
-    method public int getMaxManifestReceiverApiLevel();
-    method public void setMaxManifestReceiverApiLevel(int);
+    method @Deprecated public int getMaxManifestReceiverApiLevel();
+    method @Deprecated public void setMaxManifestReceiverApiLevel(int);
   }
 
   public abstract class HomeVisibilityListener {
@@ -138,6 +138,8 @@
   public class AudioManager {
     method public void adjustStreamVolumeForUid(int, int, int, @NonNull String, int, int, int);
     method public void adjustSuggestedStreamVolumeForUid(int, int, int, @NonNull String, int, int, int);
+    method @NonNull public java.util.List<android.bluetooth.BluetoothCodecConfig> getHwOffloadFormatsSupportedForA2dp();
+    method @NonNull public java.util.List<android.bluetooth.BluetoothLeAudioCodecConfig> getHwOffloadFormatsSupportedForLeAudio();
     method @RequiresPermission("android.permission.BLUETOOTH_STACK") public void handleBluetoothActiveDeviceChanged(@Nullable android.bluetooth.BluetoothDevice, @Nullable android.bluetooth.BluetoothDevice, @NonNull android.media.BtProfileConnectionInfo);
     method @RequiresPermission("android.permission.BLUETOOTH_STACK") public void setA2dpSuspended(boolean);
     method @RequiresPermission("android.permission.BLUETOOTH_STACK") public void setBluetoothHeadsetProperties(@NonNull String, boolean, boolean);
@@ -215,10 +217,6 @@
 
 package android.net {
 
-  public final class ConnectivityFrameworkInitializerTiramisu {
-    method public static void registerServiceWrappers();
-  }
-
   public final class EthernetNetworkSpecifier extends android.net.NetworkSpecifier implements android.os.Parcelable {
     ctor public EthernetNetworkSpecifier(@NonNull String);
     method public int describeContents();
@@ -227,6 +225,10 @@
     field @NonNull public static final android.os.Parcelable.Creator<android.net.EthernetNetworkSpecifier> CREATOR;
   }
 
+  public final class IpSecManager {
+    field public static final int DIRECTION_FWD = 2; // 0x2
+  }
+
   public static final class IpSecManager.UdpEncapsulationSocket implements java.lang.AutoCloseable {
     method public int getResourceId();
   }
@@ -256,6 +258,43 @@
     field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkStateSnapshot> CREATOR;
   }
 
+  public final class NetworkTemplate implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getDefaultNetworkStatus();
+    method public int getMatchRule();
+    method public int getMeteredness();
+    method public int getOemManaged();
+    method public int getRatType();
+    method public int getRoaming();
+    method @NonNull public java.util.Set<java.lang.String> getSubscriberIds();
+    method @NonNull public java.util.Set<java.lang.String> getWifiNetworkKeys();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkTemplate> CREATOR;
+    field public static final int MATCH_BLUETOOTH = 8; // 0x8
+    field public static final int MATCH_CARRIER = 10; // 0xa
+    field public static final int MATCH_ETHERNET = 5; // 0x5
+    field public static final int MATCH_MOBILE = 1; // 0x1
+    field public static final int MATCH_WIFI = 4; // 0x4
+    field public static final int NETWORK_TYPE_ALL = -1; // 0xffffffff
+    field public static final int OEM_MANAGED_ALL = -1; // 0xffffffff
+    field public static final int OEM_MANAGED_NO = 0; // 0x0
+    field public static final int OEM_MANAGED_PAID = 1; // 0x1
+    field public static final int OEM_MANAGED_PRIVATE = 2; // 0x2
+    field public static final int OEM_MANAGED_YES = -2; // 0xfffffffe
+  }
+
+  public static final class NetworkTemplate.Builder {
+    ctor public NetworkTemplate.Builder(int);
+    method @NonNull public android.net.NetworkTemplate build();
+    method @NonNull public android.net.NetworkTemplate.Builder setDefaultNetworkStatus(int);
+    method @NonNull public android.net.NetworkTemplate.Builder setMeteredness(int);
+    method @NonNull public android.net.NetworkTemplate.Builder setOemManaged(int);
+    method @NonNull public android.net.NetworkTemplate.Builder setRatType(int);
+    method @NonNull public android.net.NetworkTemplate.Builder setRoaming(int);
+    method @NonNull public android.net.NetworkTemplate.Builder setSubscriberIds(@NonNull java.util.Set<java.lang.String>);
+    method @NonNull public android.net.NetworkTemplate.Builder setWifiNetworkKeys(@NonNull java.util.Set<java.lang.String>);
+  }
+
   public class NetworkWatchlistManager {
     method @Nullable public byte[] getWatchlistConfigHash();
   }
@@ -340,6 +379,10 @@
     method @Nullable public android.os.IBinder getOrThrow() throws android.os.StatsServiceManager.ServiceNotFoundException;
   }
 
+  public final class StrictMode {
+    method public static void noteUntaggedSocket();
+  }
+
   public class SystemConfigManager {
     method @NonNull public java.util.List<android.content.ComponentName> getEnabledComponentOverrides(@NonNull String);
   }
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 6e1ab91..1f96a24 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -240,6 +240,7 @@
     field public static final String READ_PRIVILEGED_PHONE_STATE = "android.permission.READ_PRIVILEGED_PHONE_STATE";
     field public static final String READ_PROJECTION_STATE = "android.permission.READ_PROJECTION_STATE";
     field public static final String READ_RUNTIME_PROFILES = "android.permission.READ_RUNTIME_PROFILES";
+    field public static final String READ_SAFETY_CENTER_STATUS = "android.permission.READ_SAFETY_CENTER_STATUS";
     field public static final String READ_SEARCH_INDEXABLES = "android.permission.READ_SEARCH_INDEXABLES";
     field public static final String READ_SYSTEM_UPDATE_INFO = "android.permission.READ_SYSTEM_UPDATE_INFO";
     field public static final String READ_WALLPAPER_INTERNAL = "android.permission.READ_WALLPAPER_INTERNAL";
@@ -297,6 +298,7 @@
     field public static final String SIGNAL_REBOOT_READINESS = "android.permission.SIGNAL_REBOOT_READINESS";
     field public static final String SOUND_TRIGGER_RUN_IN_BATTERY_SAVER = "android.permission.SOUND_TRIGGER_RUN_IN_BATTERY_SAVER";
     field public static final String START_ACTIVITIES_FROM_BACKGROUND = "android.permission.START_ACTIVITIES_FROM_BACKGROUND";
+    field public static final String START_REVIEW_PERMISSION_DECISIONS = "android.permission.START_REVIEW_PERMISSION_DECISIONS";
     field public static final String STATUS_BAR_SERVICE = "android.permission.STATUS_BAR_SERVICE";
     field public static final String STOP_APP_SWITCHES = "android.permission.STOP_APP_SWITCHES";
     field public static final String SUBSTITUTE_NOTIFICATION_APP_NAME = "android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME";
@@ -340,10 +342,12 @@
 
   public static final class R.array {
     field public static final int config_keySystemUuidMapping = 17235973; // 0x1070005
+    field public static final int config_optionalIpSecAlgorithms;
   }
 
   public static final class R.attr {
     field public static final int allowClearUserDataOnFailedRestore = 16844288; // 0x1010600
+    field public static final int gameSessionService;
     field public static final int hotwordDetectionService = 16844326; // 0x1010626
     field public static final int isVrOnly = 16844152; // 0x1010578
     field public static final int minExtensionVersion = 16844305; // 0x1010611
@@ -722,12 +726,14 @@
   }
 
   public class BroadcastOptions {
+    method public void clearRequireCompatChange();
     method public boolean isPendingIntentBackgroundActivityLaunchAllowed();
     method public static android.app.BroadcastOptions makeBasic();
     method @RequiresPermission(android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND) public void setBackgroundActivityStartsAllowed(boolean);
     method public void setDontSendToRestrictedApps(boolean);
     method public void setPendingIntentBackgroundActivityLaunchAllowed(boolean);
     method public void setRequireAllOfPermissions(@Nullable String[]);
+    method public void setRequireCompatChange(long, boolean);
     method public void setRequireNoneOfPermissions(@Nullable String[]);
     method @RequiresPermission(anyOf={android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST, android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND, android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND}) public void setTemporaryAppAllowlist(long, int, int, @Nullable String);
     method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST, android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND, android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND}) public void setTemporaryAppWhitelistDuration(long);
@@ -853,7 +859,11 @@
 
   public class StatusBarManager {
     method @NonNull @RequiresPermission(android.Manifest.permission.STATUS_BAR) public android.app.StatusBarManager.DisableInfo getDisableInfo();
+    method @RequiresPermission(android.Manifest.permission.STATUS_BAR) public int getNavBarModeOverride();
     method @RequiresPermission(android.Manifest.permission.STATUS_BAR) public void setDisabledForSetup(boolean);
+    method @RequiresPermission(android.Manifest.permission.STATUS_BAR) public void setNavBarModeOverride(int);
+    field public static final int NAV_BAR_MODE_OVERRIDE_KIDS = 1; // 0x1
+    field public static final int NAV_BAR_MODE_OVERRIDE_NONE = 0; // 0x0
   }
 
   public static final class StatusBarManager.DisableInfo {
@@ -1398,7 +1408,9 @@
     method public static boolean isChangeEnabled(long);
     method @RequiresPermission(allOf={"android.permission.READ_COMPAT_CHANGE_CONFIG", "android.permission.LOG_COMPAT_CHANGE"}) public static boolean isChangeEnabled(long, @NonNull String, @NonNull android.os.UserHandle);
     method @RequiresPermission(allOf={"android.permission.READ_COMPAT_CHANGE_CONFIG", "android.permission.LOG_COMPAT_CHANGE"}) public static boolean isChangeEnabled(long, int);
+    method @RequiresPermission(android.Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD) public static void putAllPackageOverrides(@NonNull java.util.Map<java.lang.String,java.util.Map<java.lang.Long,android.app.compat.PackageOverride>>);
     method @RequiresPermission(android.Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD) public static void putPackageOverrides(@NonNull String, @NonNull java.util.Map<java.lang.Long,android.app.compat.PackageOverride>);
+    method @RequiresPermission(android.Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD) public static void removeAllPackageOverrides(@NonNull java.util.Map<java.lang.String,java.util.Set<java.lang.Long>>);
     method @RequiresPermission(android.Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD) public static void removePackageOverrides(@NonNull String, @NonNull java.util.Set<java.lang.Long>);
   }
 
@@ -2585,6 +2597,7 @@
     field public static final String HDMI_CONTROL_SERVICE = "hdmi_control";
     field public static final String MEDIA_TRANSCODING_SERVICE = "media_transcoding";
     field public static final String MUSIC_RECOGNITION_SERVICE = "music_recognition";
+    field public static final String NEARBY_SERVICE = "nearby";
     field public static final String NETD_SERVICE = "netd";
     field @Deprecated public static final String NETWORK_SCORE_SERVICE = "network_score";
     field public static final String OEM_LOCK_SERVICE = "oem_lock";
@@ -2655,6 +2668,7 @@
     field public static final String ACTION_PENDING_INCIDENT_REPORTS_CHANGED = "android.intent.action.PENDING_INCIDENT_REPORTS_CHANGED";
     field public static final String ACTION_PRE_BOOT_COMPLETED = "android.intent.action.PRE_BOOT_COMPLETED";
     field public static final String ACTION_QUERY_PACKAGE_RESTART = "android.intent.action.QUERY_PACKAGE_RESTART";
+    field public static final String ACTION_REFRESH_SAFETY_SOURCES = "android.intent.action.REFRESH_SAFETY_SOURCES";
     field public static final String ACTION_RESOLVE_INSTANT_APP_PACKAGE = "android.intent.action.RESOLVE_INSTANT_APP_PACKAGE";
     field @RequiresPermission(android.Manifest.permission.REVIEW_ACCESSIBILITY_SERVICES) public static final String ACTION_REVIEW_ACCESSIBILITY_SERVICES = "android.intent.action.REVIEW_ACCESSIBILITY_SERVICES";
     field @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS) public static final String ACTION_REVIEW_ONGOING_PERMISSION_USAGE = "android.intent.action.REVIEW_ONGOING_PERMISSION_USAGE";
@@ -2685,6 +2699,10 @@
     field public static final String EXTRA_PACKAGES = "android.intent.extra.PACKAGES";
     field public static final String EXTRA_PERMISSION_NAME = "android.intent.extra.PERMISSION_NAME";
     field public static final String EXTRA_REASON = "android.intent.extra.REASON";
+    field public static final int EXTRA_REFRESH_REQUEST_TYPE_FETCH_FRESH_DATA = 0; // 0x0
+    field public static final int EXTRA_REFRESH_REQUEST_TYPE_GET_DATA = 1; // 0x1
+    field public static final String EXTRA_REFRESH_SAFETY_SOURCES_REQUEST_TYPE = "android.intent.extra.REFRESH_SAFETY_SOURCES_REQUEST_TYPE";
+    field public static final String EXTRA_REFRESH_SAFETY_SOURCE_IDS = "android.intent.extra.REFRESH_SAFETY_SOURCE_IDS";
     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";
@@ -2904,6 +2922,7 @@
   }
 
   public static class LauncherApps.ShortcutQuery {
+    field public static final int FLAG_GET_PERSISTED_DATA = 4096; // 0x1000
     field @RequiresPermission(android.Manifest.permission.ACCESS_SHORTCUTS) public static final int FLAG_GET_PERSONS_DATA = 2048; // 0x800
   }
 
@@ -5132,6 +5151,9 @@
   public static final class GnssSingleSatCorrection.Builder {
     ctor public GnssSingleSatCorrection.Builder();
     method @NonNull public android.location.GnssSingleSatCorrection build();
+    method @NonNull public android.location.GnssSingleSatCorrection.Builder clearExcessPathLengthMeters();
+    method @NonNull public android.location.GnssSingleSatCorrection.Builder clearExcessPathLengthUncertaintyMeters();
+    method @NonNull public android.location.GnssSingleSatCorrection.Builder clearProbabilityLineOfSight();
     method @NonNull public android.location.GnssSingleSatCorrection.Builder setCarrierFrequencyHz(@FloatRange(from=0.0f, fromInclusive=false) float);
     method @NonNull public android.location.GnssSingleSatCorrection.Builder setConstellationType(int);
     method @NonNull public android.location.GnssSingleSatCorrection.Builder setExcessPathLengthMeters(@FloatRange(from=0.0f) float);
@@ -5657,6 +5679,7 @@
     method @NonNull @RequiresPermission(android.Manifest.permission.CALL_AUDIO_INTERCEPTION) public android.media.AudioTrack getCallUplinkInjectionAudioTrack(@NonNull android.media.AudioFormat);
     method @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_AUDIO_ROUTING, "android.permission.QUERY_AUDIO_STATE"}) public int getDeviceVolumeBehavior(@NonNull android.media.AudioDeviceAttributes);
     method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_AUDIO_ROUTING, "android.permission.QUERY_AUDIO_STATE"}) public java.util.List<android.media.AudioDeviceAttributes> getDevicesForAttributes(@NonNull android.media.AudioAttributes);
+    method @RequiresPermission("android.permission.QUERY_AUDIO_STATE") public int getLastAudibleStreamVolume(int);
     method @IntRange(from=0) public long getMaxAdditionalOutputDeviceDelay(@NonNull android.media.AudioDeviceInfo);
     method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMaxVolumeIndexForAttributes(@NonNull android.media.AudioAttributes);
     method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMinVolumeIndexForAttributes(@NonNull android.media.AudioAttributes);
@@ -6298,9 +6321,11 @@
     method @Nullable @RequiresPermission(android.Manifest.permission.TV_INPUT_HARDWARE) public android.media.tv.TvInputManager.Hardware acquireTvInputHardware(int, @NonNull android.media.tv.TvInputInfo, @Nullable String, int, @NonNull java.util.concurrent.Executor, @NonNull android.media.tv.TvInputManager.HardwareCallback);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PARENTAL_CONTROLS) public void addBlockedRating(@NonNull android.media.tv.TvContentRating);
     method @RequiresPermission(android.Manifest.permission.CAPTURE_TV_INPUT) public boolean captureFrame(String, android.view.Surface, android.media.tv.TvStreamConfig);
+    method @NonNull public java.util.List<java.lang.String> getAvailableExtensionInterfaceNames(@NonNull String);
     method @RequiresPermission(android.Manifest.permission.CAPTURE_TV_INPUT) public java.util.List<android.media.tv.TvStreamConfig> getAvailableTvStreamConfigList(String);
     method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_TUNED_INFO) public java.util.List<android.media.tv.TunedInfo> getCurrentTunedInfos();
     method @NonNull @RequiresPermission("android.permission.DVB_DEVICE") public java.util.List<android.media.tv.DvbDeviceInfo> getDvbDeviceList();
+    method @Nullable public android.os.IBinder getExtensionInterface(@NonNull String, @NonNull String);
     method @RequiresPermission(android.Manifest.permission.TV_INPUT_HARDWARE) public java.util.List<android.media.tv.TvInputHardwareInfo> getHardwareList();
     method @RequiresPermission(android.Manifest.permission.READ_CONTENT_RATING_SYSTEMS) public java.util.List<android.media.tv.TvContentRatingSystemInfo> getTvContentRatingSystemList();
     method @RequiresPermission(android.Manifest.permission.CAPTURE_TV_INPUT) public boolean isSingleSessionActive();
@@ -6331,6 +6356,9 @@
 
   public abstract class TvInputService extends android.app.Service {
     method @Nullable public android.os.IBinder createExtension();
+    method @NonNull public java.util.List<java.lang.String> getAvailableExtensionInterfaceNames();
+    method @Nullable public android.os.IBinder getExtensionInterface(@NonNull String);
+    method @Nullable public String getExtensionInterfacePermission(@NonNull String);
     method @Nullable public android.media.tv.TvInputInfo onHardwareAdded(android.media.tv.TvInputHardwareInfo);
     method @Nullable public String onHardwareRemoved(android.media.tv.TvInputHardwareInfo);
     method @Nullable public android.media.tv.TvInputInfo onHdmiDeviceAdded(android.hardware.hdmi.HdmiDeviceInfo);
@@ -6458,9 +6486,11 @@
     method public int getAvSyncHwId(@NonNull android.media.tv.tuner.filter.Filter);
     method public long getAvSyncTime(int);
     method @Nullable public java.util.List<android.media.tv.tuner.frontend.FrontendInfo> getAvailableFrontendInfos();
+    method @Nullable public String getCurrentFrontendHardwareInfo();
     method @Nullable public android.media.tv.tuner.DemuxCapabilities getDemuxCapabilities();
     method @Nullable public android.media.tv.tuner.frontend.FrontendInfo getFrontendInfo();
     method @Nullable public android.media.tv.tuner.frontend.FrontendStatus getFrontendStatus(@NonNull int[]);
+    method @IntRange(from=0xffffffff) public int getMaxNumberOfFrontends(int);
     method @RequiresPermission("android.permission.TUNER_RESOURCE_ACCESS") public boolean hasUnusedFrontend(int);
     method public boolean isLowestPriority(int);
     method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_TV_DESCRAMBLER) public android.media.tv.tuner.Descrambler openDescrambler();
@@ -6473,6 +6503,7 @@
     method @Nullable public android.media.tv.tuner.filter.TimeFilter openTimeFilter();
     method public int scan(@NonNull android.media.tv.tuner.frontend.FrontendSettings, int, @NonNull java.util.concurrent.Executor, @NonNull android.media.tv.tuner.frontend.ScanCallback);
     method public int setLnaEnabled(boolean);
+    method public int setMaxNumberOfFrontends(int, @IntRange(from=0) int);
     method public void setOnTuneEventListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.tv.tuner.frontend.OnTuneEventListener);
     method public void setResourceLostListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.tv.tuner.Tuner.OnResourceLostListener);
     method public void shareFrontendFromTuner(@NonNull android.media.tv.tuner.Tuner);
@@ -6622,6 +6653,10 @@
     method public boolean isPassthrough();
     method public boolean useSecureMemory();
     field public static final int AUDIO_STREAM_TYPE_AAC = 6; // 0x6
+    field public static final int AUDIO_STREAM_TYPE_AAC_ADTS = 16; // 0x10
+    field public static final int AUDIO_STREAM_TYPE_AAC_HE_ADTS = 18; // 0x12
+    field public static final int AUDIO_STREAM_TYPE_AAC_HE_LATM = 19; // 0x13
+    field public static final int AUDIO_STREAM_TYPE_AAC_LATM = 17; // 0x11
     field public static final int AUDIO_STREAM_TYPE_AC3 = 7; // 0x7
     field public static final int AUDIO_STREAM_TYPE_AC4 = 9; // 0x9
     field public static final int AUDIO_STREAM_TYPE_DRA = 15; // 0xf
@@ -6685,6 +6720,8 @@
     method @Nullable public String acquireSharedFilterToken();
     method public void close();
     method public int configure(@NonNull android.media.tv.tuner.filter.FilterConfiguration);
+    method public int delayCallbackUntilBufferFilled(int);
+    method public int delayCallbackUntilTimeMillis(long);
     method public int flush();
     method public void freeSharedFilterToken(@NonNull String);
     method @Deprecated public int getId();
@@ -6783,6 +6820,7 @@
     method @IntRange(from=0) public int getMpuSequenceNumber();
     method public long getOffset();
     method public long getPts();
+    method public int getScIndexMask();
     method public int getStreamId();
     method public boolean isDtsPresent();
     method public boolean isPrivateData();
@@ -7605,6 +7643,7 @@
     method public int getBer();
     method @NonNull public int[] getBers();
     method @NonNull public int[] getCodeRates();
+    method @NonNull public int[] getDvbtCellIds();
     method @NonNull public int[] getExtendedModulations();
     method @Deprecated public int getFreqOffset();
     method public long getFreqOffsetLong();
@@ -7647,6 +7686,7 @@
     field public static final int FRONTEND_STATUS_TYPE_BERS = 23; // 0x17
     field public static final int FRONTEND_STATUS_TYPE_CODERATES = 24; // 0x18
     field public static final int FRONTEND_STATUS_TYPE_DEMOD_LOCK = 0; // 0x0
+    field public static final int FRONTEND_STATUS_TYPE_DVBT_CELL_IDS = 40; // 0x28
     field public static final int FRONTEND_STATUS_TYPE_EWBS = 13; // 0xd
     field public static final int FRONTEND_STATUS_TYPE_FEC = 8; // 0x8
     field public static final int FRONTEND_STATUS_TYPE_FREQ_OFFSET = 18; // 0x12
@@ -7881,6 +7921,7 @@
     method public void onAtsc3PlpInfosReported(@NonNull android.media.tv.tuner.frontend.Atsc3PlpInfo[]);
     method public default void onDvbcAnnexReported(int);
     method public void onDvbsStandardReported(int);
+    method public default void onDvbtCellIdsReported(@NonNull int[]);
     method public void onDvbtStandardReported(int);
     method public default void onFrequenciesLongReported(@NonNull long[]);
     method @Deprecated public void onFrequenciesReported(@NonNull int[]);
@@ -7895,6 +7936,7 @@
     method public void onScanStopped();
     method public void onSignalTypeReported(int);
     method public void onSymbolRatesReported(@NonNull int[]);
+    method public default void onUnlocked();
   }
 
 }
@@ -8054,13 +8096,17 @@
     method @NonNull public android.net.NetworkStats subtract(@NonNull android.net.NetworkStats);
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkStats> CREATOR;
+    field public static final int DEFAULT_NETWORK_ALL = -1; // 0xffffffff
     field public static final int DEFAULT_NETWORK_NO = 0; // 0x0
     field public static final int DEFAULT_NETWORK_YES = 1; // 0x1
     field public static final String IFACE_VT = "vt_data0";
+    field public static final int METERED_ALL = -1; // 0xffffffff
     field public static final int METERED_NO = 0; // 0x0
     field public static final int METERED_YES = 1; // 0x1
+    field public static final int ROAMING_ALL = -1; // 0xffffffff
     field public static final int ROAMING_NO = 0; // 0x0
     field public static final int ROAMING_YES = 1; // 0x1
+    field public static final int SET_ALL = -1; // 0xffffffff
     field public static final int SET_DEFAULT = 0; // 0x0
     field public static final int SET_FOREGROUND = 1; // 0x1
     field public static final int TAG_NONE = 0; // 0x0
@@ -9504,6 +9550,7 @@
   public final class PermissionControllerManager {
     method @RequiresPermission(anyOf={android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS, android.Manifest.permission.RESTORE_RUNTIME_PERMISSIONS}) public void applyStagedRuntimePermissionBackup(@NonNull String, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
     method @RequiresPermission(android.Manifest.permission.GET_RUNTIME_PERMISSIONS) public void getRuntimePermissionBackup(@NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<byte[]>);
+    method public void getUnusedAppCount(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.IntConsumer);
     method @RequiresPermission(android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS) public void revokeRuntimePermissions(@NonNull java.util.Map<java.lang.String,java.util.List<java.lang.String>>, boolean, int, @NonNull java.util.concurrent.Executor, @NonNull android.permission.PermissionControllerManager.OnRevokeRuntimePermissionsCallback);
     method @RequiresPermission(anyOf={android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS, android.Manifest.permission.RESTORE_RUNTIME_PERMISSIONS}) public void stageAndApplyRuntimePermissionsBackup(@NonNull byte[], @NonNull android.os.UserHandle);
     field public static final int COUNT_ONLY_WHEN_GRANTED = 1; // 0x1
@@ -9528,6 +9575,7 @@
     method @BinderThread public abstract void onGetPermissionUsages(boolean, long, @NonNull java.util.function.Consumer<java.util.List<android.permission.RuntimePermissionUsageInfo>>);
     method @BinderThread public void onGetPlatformPermissionsForGroup(@NonNull String, @NonNull java.util.function.Consumer<java.util.List<java.lang.String>>);
     method @BinderThread public abstract void onGetRuntimePermissionsBackup(@NonNull android.os.UserHandle, @NonNull java.io.OutputStream, @NonNull Runnable);
+    method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_APP_HIBERNATION) public void onGetUnusedAppCount(@NonNull java.util.function.IntConsumer);
     method @BinderThread public abstract void onGrantOrUpgradeDefaultRuntimePermissions(@NonNull Runnable);
     method @BinderThread public void onOneTimePermissionSessionTimeout(@NonNull String);
     method @Deprecated @BinderThread public void onRestoreDelayedRuntimePermissionsBackup(@NonNull String, @NonNull android.os.UserHandle, @NonNull java.util.function.Consumer<java.lang.Boolean>);
@@ -9554,6 +9602,7 @@
     method @RequiresPermission(anyOf={android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY, android.Manifest.permission.UPGRADE_RUNTIME_PERMISSIONS}) public void setRuntimePermissionsVersion(@IntRange(from=0) int);
     method @RequiresPermission(android.Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS) public void startOneTimePermissionSession(@NonNull String, long, int, int);
     method @RequiresPermission(android.Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS) public void stopOneTimePermissionSession(@NonNull String);
+    field @RequiresPermission(android.Manifest.permission.START_REVIEW_PERMISSION_DECISIONS) public static final String ACTION_REVIEW_PERMISSION_DECISIONS = "android.permission.action.REVIEW_PERMISSION_DECISIONS";
     field public static final int PERMISSION_GRANTED = 0; // 0x0
     field public static final int PERMISSION_HARD_DENIED = 2; // 0x2
     field public static final int PERMISSION_SOFT_DENIED = 1; // 0x1
@@ -9975,7 +10024,7 @@
     method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public static void resetToDefaults(@NonNull android.content.ContentResolver, @Nullable String);
     field public static final String AIRPLANE_MODE_TOGGLEABLE_RADIOS = "airplane_mode_toggleable_radios";
     field public static final String APP_STANDBY_ENABLED = "app_standby_enabled";
-    field public static final String AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES = "autofill_compat_mode_allowed_packages";
+    field @Deprecated public static final String AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES = "autofill_compat_mode_allowed_packages";
     field public static final String CARRIER_APP_NAMES = "carrier_app_names";
     field public static final String CARRIER_APP_WHITELIST = "carrier_app_whitelist";
     field public static final String DEFAULT_SM_DP_PLUS = "default_sm_dp_plus";
@@ -10689,6 +10738,7 @@
     field public static final String EXTRA_RESOLUTION_CONFIRMATION_CODE_RETRIED = "android.service.euicc.extra.RESOLUTION_CONFIRMATION_CODE_RETRIED";
     field public static final String EXTRA_RESOLUTION_CONSENT = "android.service.euicc.extra.RESOLUTION_CONSENT";
     field public static final String EXTRA_RESOLUTION_PORT_INDEX = "android.service.euicc.extra.RESOLUTION_PORT_INDEX";
+    field public static final String EXTRA_RESOLUTION_USE_PORT_INDEX = "android.service.euicc.extra.RESOLUTION_USE_PORT_INDEX";
     field public static final String EXTRA_RESOLVABLE_ERRORS = "android.service.euicc.extra.RESOLVABLE_ERRORS";
     field public static final int RESOLVABLE_ERROR_CONFIRMATION_CODE = 1; // 0x1
     field public static final int RESOLVABLE_ERROR_POLICY_RULES = 2; // 0x2
@@ -10736,12 +10786,35 @@
 
 package android.service.games {
 
+  public final class CreateGameSessionRequest implements android.os.Parcelable {
+    ctor public CreateGameSessionRequest(int, @NonNull String);
+    method public int describeContents();
+    method @NonNull public String getGamePackageName();
+    method public int getTaskId();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.service.games.CreateGameSessionRequest> CREATOR;
+  }
+
   public class GameService extends android.app.Service {
     ctor public GameService();
     method @Nullable public android.os.IBinder onBind(@Nullable android.content.Intent);
     method public void onConnected();
     method public void onDisconnected();
-    field public static final String SERVICE_INTERFACE = "android.service.games.GameService";
+    field public static final String ACTION_GAME_SERVICE = "android.service.games.action.GAME_SERVICE";
+    field public static final String SERVICE_META_DATA = "android.game_service";
+  }
+
+  public abstract class GameSession {
+    ctor public GameSession();
+    method public void onCreate();
+    method public void onDestroy();
+  }
+
+  public abstract class GameSessionService extends android.app.Service {
+    ctor public GameSessionService();
+    method @Nullable public android.os.IBinder onBind(@Nullable android.content.Intent);
+    method @NonNull public abstract android.service.games.GameSession onNewSession(@NonNull android.service.games.CreateGameSessionRequest);
+    field public static final String ACTION_GAME_SESSION_SERVICE = "android.service.games.action.GAME_SESSION_SERVICE";
   }
 
 }
@@ -13086,21 +13159,23 @@
 
   public final class DataProfile implements android.os.Parcelable {
     method public int describeContents();
-    method @NonNull public String getApn();
-    method public int getAuthType();
-    method public int getBearerBitmask();
+    method @Deprecated @NonNull public String getApn();
+    method @Nullable public android.telephony.data.ApnSetting getApnSetting();
+    method @Deprecated public int getAuthType();
+    method @Deprecated public int getBearerBitmask();
     method @Deprecated public int getMtu();
-    method public int getMtuV4();
-    method public int getMtuV6();
-    method @Nullable public String getPassword();
-    method public int getProfileId();
-    method public int getProtocolType();
-    method public int getRoamingProtocolType();
-    method public int getSupportedApnTypesBitmask();
+    method @Deprecated public int getMtuV4();
+    method @Deprecated public int getMtuV6();
+    method @Deprecated @Nullable public String getPassword();
+    method @Deprecated public int getProfileId();
+    method @Deprecated public int getProtocolType();
+    method @Deprecated public int getRoamingProtocolType();
+    method @Deprecated public int getSupportedApnTypesBitmask();
+    method @Nullable public android.telephony.data.TrafficDescriptor getTrafficDescriptor();
     method public int getType();
-    method @Nullable public String getUserName();
+    method @Deprecated @Nullable public String getUserName();
     method public boolean isEnabled();
-    method public boolean isPersistent();
+    method @Deprecated public boolean isPersistent();
     method public boolean isPreferred();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.DataProfile> CREATOR;
@@ -13113,21 +13188,23 @@
     ctor public DataProfile.Builder();
     method @NonNull public android.telephony.data.DataProfile build();
     method @NonNull public android.telephony.data.DataProfile.Builder enable(boolean);
-    method @NonNull public android.telephony.data.DataProfile.Builder setApn(@NonNull String);
-    method @NonNull public android.telephony.data.DataProfile.Builder setAuthType(int);
-    method @NonNull public android.telephony.data.DataProfile.Builder setBearerBitmask(int);
+    method @Deprecated @NonNull public android.telephony.data.DataProfile.Builder setApn(@NonNull String);
+    method @NonNull public android.telephony.data.DataProfile.Builder setApnSetting(@NonNull android.telephony.data.ApnSetting);
+    method @Deprecated @NonNull public android.telephony.data.DataProfile.Builder setAuthType(int);
+    method @Deprecated @NonNull public android.telephony.data.DataProfile.Builder setBearerBitmask(int);
     method @Deprecated @NonNull public android.telephony.data.DataProfile.Builder setMtu(int);
-    method @NonNull public android.telephony.data.DataProfile.Builder setMtuV4(int);
-    method @NonNull public android.telephony.data.DataProfile.Builder setMtuV6(int);
-    method @NonNull public android.telephony.data.DataProfile.Builder setPassword(@NonNull String);
-    method @NonNull public android.telephony.data.DataProfile.Builder setPersistent(boolean);
+    method @Deprecated @NonNull public android.telephony.data.DataProfile.Builder setMtuV4(int);
+    method @Deprecated @NonNull public android.telephony.data.DataProfile.Builder setMtuV6(int);
+    method @Deprecated @NonNull public android.telephony.data.DataProfile.Builder setPassword(@NonNull String);
+    method @Deprecated @NonNull public android.telephony.data.DataProfile.Builder setPersistent(boolean);
     method @NonNull public android.telephony.data.DataProfile.Builder setPreferred(boolean);
-    method @NonNull public android.telephony.data.DataProfile.Builder setProfileId(int);
-    method @NonNull public android.telephony.data.DataProfile.Builder setProtocolType(int);
-    method @NonNull public android.telephony.data.DataProfile.Builder setRoamingProtocolType(int);
-    method @NonNull public android.telephony.data.DataProfile.Builder setSupportedApnTypesBitmask(int);
+    method @Deprecated @NonNull public android.telephony.data.DataProfile.Builder setProfileId(int);
+    method @Deprecated @NonNull public android.telephony.data.DataProfile.Builder setProtocolType(int);
+    method @Deprecated @NonNull public android.telephony.data.DataProfile.Builder setRoamingProtocolType(int);
+    method @Deprecated @NonNull public android.telephony.data.DataProfile.Builder setSupportedApnTypesBitmask(int);
+    method @NonNull public android.telephony.data.DataProfile.Builder setTrafficDescriptor(@NonNull android.telephony.data.TrafficDescriptor);
     method @NonNull public android.telephony.data.DataProfile.Builder setType(int);
-    method @NonNull public android.telephony.data.DataProfile.Builder setUserName(@NonNull String);
+    method @Deprecated @NonNull public android.telephony.data.DataProfile.Builder setUserName(@NonNull String);
   }
 
   public abstract class DataService extends android.app.Service {
@@ -13259,8 +13336,7 @@
     method public void authenticateServer(String, String, byte[], byte[], byte[], byte[], java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<byte[]>);
     method public void cancelSession(String, byte[], @android.telephony.euicc.EuiccCardManager.CancelReason int, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<byte[]>);
     method public void deleteProfile(String, String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<java.lang.Void>);
-    method @Deprecated public void disableProfile(String, String, boolean, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<java.lang.Void>);
-    method public void disableProfile(@Nullable String, @Nullable String, int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.euicc.EuiccCardManager.ResultCallback<java.lang.Void>);
+    method public void disableProfile(String, String, boolean, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<java.lang.Void>);
     method public void listNotifications(String, @android.telephony.euicc.EuiccNotification.Event int, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<android.telephony.euicc.EuiccNotification[]>);
     method public void loadBoundProfilePackage(String, byte[], java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<byte[]>);
     method public void prepareDownload(String, @Nullable byte[], byte[], byte[], byte[], java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<byte[]>);
@@ -13709,6 +13785,7 @@
     field public static final int OIR_PRESENTATION_NOT_RESTRICTED = 2; // 0x2
     field public static final int OIR_PRESENTATION_PAYPHONE = 4; // 0x4
     field public static final int OIR_PRESENTATION_RESTRICTED = 1; // 0x1
+    field public static final int OIR_PRESENTATION_UNAVAILABLE = 5; // 0x5
     field public static final int OIR_PRESENTATION_UNKNOWN = 3; // 0x3
     field public static final int PRIORITY_NORMAL = 0; // 0x0
     field public static final int PRIORITY_URGENT = 1; // 0x1
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 691fec4..0710781 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -59,6 +59,7 @@
   public static final class R.bool {
     field public static final int config_assistantOnTopOfDream = 17891333; // 0x1110005
     field public static final int config_perDisplayFocusEnabled = 17891332; // 0x1110004
+    field public static final int config_preventImeStartupUnlessTextEditor;
     field public static final int config_remoteInsetsControllerControlsSystemBars = 17891334; // 0x1110006
   }
 
@@ -248,12 +249,15 @@
 
   public class BroadcastOptions {
     ctor public BroadcastOptions(@NonNull android.os.Bundle);
-    method public int getMaxManifestReceiverApiLevel();
+    method @Deprecated public int getMaxManifestReceiverApiLevel();
     method public long getTemporaryAppAllowlistDuration();
     method @Nullable public String getTemporaryAppAllowlistReason();
     method public int getTemporaryAppAllowlistReasonCode();
     method public int getTemporaryAppAllowlistType();
-    method public void setMaxManifestReceiverApiLevel(int);
+    method @Deprecated public void setMaxManifestReceiverApiLevel(int);
+    method public boolean testRequireCompatChange(int);
+    field public static final long CHANGE_ALWAYS_DISABLED = 210856463L; // 0xc916a0fL
+    field public static final long CHANGE_ALWAYS_ENABLED = 209888056L; // 0xc82a338L
   }
 
   public class DownloadManager {
@@ -699,6 +703,7 @@
     field public static final String FONT_SERVICE = "font";
     field public static final String POWER_EXEMPTION_SERVICE = "power_exemption";
     field @Deprecated public static final String POWER_WHITELIST_MANAGER = "power_whitelist";
+    field @Deprecated public static final int RECEIVER_EXPORTED_UNAUDITED = 2; // 0x2
     field public static final String TEST_NETWORK_SERVICE = "test_network";
   }
 
@@ -1428,6 +1433,9 @@
     field public static final int DEVICE_ROLE_DISABLED = 2; // 0x2
     field public static final int DEVICE_ROLE_NONE = 0; // 0x0
     field public static final int DEVICE_ROLE_PREFERRED = 1; // 0x1
+    field public static final int DIRECT_BITSTREAM_SUPPORTED = 4; // 0x4
+    field public static final int DIRECT_OFFLOAD_GAPLESS_SUPPORTED = 3; // 0x3
+    field public static final int DIRECT_OFFLOAD_SUPPORTED = 1; // 0x1
     field public static final int OFFLOAD_GAPLESS_SUPPORTED = 2; // 0x2
     field public static final int OFFLOAD_SUPPORTED = 1; // 0x1
     field public static final int STREAM_DEFAULT = -1; // 0xffffffff
@@ -2083,6 +2091,7 @@
     field public static final String NAMESPACE_CONSTRAIN_DISPLAY_APIS = "constrain_display_apis";
     field public static final String NAMESPACE_DEVICE_IDLE = "device_idle";
     field public static final String NAMESPACE_JOB_SCHEDULER = "jobscheduler";
+    field public static final String NAMESPACE_SELECTION_TOOLBAR = "selection_toolbar";
   }
 
   public final class Settings {
@@ -2833,7 +2842,6 @@
     method public void addChild(@NonNull android.os.IBinder);
     method public long getSourceNodeId();
     method public void setLeashedParent(@Nullable android.os.IBinder, int);
-    method public static void setNumInstancesInUseCounter(java.util.concurrent.atomic.AtomicInteger);
     method public void writeToParcelNoRecycle(android.os.Parcel, int);
   }
 
@@ -2873,6 +2881,7 @@
   }
 
   public final class AutofillManager {
+    field public static final String DEVICE_CONFIG_AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES = "compat_mode_allowed_packages";
     field public static final String DEVICE_CONFIG_AUTOFILL_SMART_SUGGESTION_SUPPORTED_MODES = "smart_suggestion_supported_modes";
     field public static final int FLAG_SMART_SUGGESTION_OFF = 0; // 0x0
     field public static final int FLAG_SMART_SUGGESTION_SYSTEM = 1; // 0x1
diff --git a/core/java/Android.bp b/core/java/Android.bp
index 343830a..c9cbef2 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -301,6 +301,17 @@
     ],
 }
 
+cc_library {
+    name: "libactivity_manager_procstate_aidl-cpp",
+    host_supported: true,
+    srcs: [
+        ":activity_manager_procstate_aidl",
+    ],
+    aidl: {
+        export_aidl_headers: true,
+    },
+}
+
 // Build Rust bindings for PermissionController. Needed by keystore2.
 aidl_interface {
     name: "android.os.permissions_aidl",
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 3d38551..9a55867 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -59,6 +59,7 @@
 import android.view.SurfaceView;
 import android.view.WindowManager;
 import android.view.WindowManagerImpl;
+import android.view.accessibility.AccessibilityCache;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityInteractionClient;
 import android.view.accessibility.AccessibilityNodeInfo;
@@ -748,7 +749,6 @@
 
     private FingerprintGestureController mFingerprintGestureController;
 
-
     /**
      * Callback for {@link android.view.accessibility.AccessibilityEvent}s.
      *
@@ -2076,6 +2076,85 @@
                 available);
     }
 
+    /** Sets the cache status.
+     *
+     * <p>If {@code enabled}, enable the cache and prefetching. Otherwise, disable the cache
+     * and prefetching.
+     * Note: By default the cache is enabled.
+     * @param enabled whether to enable or disable the cache.
+     * @return {@code true} if the cache and connection are not null, so the cache status is set.
+     */
+    public boolean setCacheEnabled(boolean enabled) {
+        AccessibilityCache cache =
+                AccessibilityInteractionClient.getCache(mConnectionId);
+        if (cache == null) {
+            return false;
+        }
+        final IAccessibilityServiceConnection connection =
+                AccessibilityInteractionClient.getConnection(mConnectionId);
+        if (connection == null) {
+            return false;
+        }
+        try {
+            connection.setCacheEnabled(enabled);
+            cache.setEnabled(enabled);
+            return true;
+        } catch (RemoteException re) {
+            Log.w(LOG_TAG, "Error while setting status of cache", re);
+            re.rethrowFromSystemServer();
+        }
+        return false;
+    }
+
+    /** Invalidates {@code node} and its subtree in the cache.
+     * @param node the node to invalidate.
+     * @return {@code true} if the subtree rooted at {@code node} was invalidated.
+     */
+    public boolean clearCachedSubtree(@NonNull AccessibilityNodeInfo node) {
+        AccessibilityCache cache =
+                AccessibilityInteractionClient.getCache(mConnectionId);
+        if (cache == null) {
+            return false;
+        }
+        return cache.clearSubTree(node);
+    }
+
+    /** Clears the cache.
+     * @return {@code true} if the cache was cleared
+     */
+    public boolean clearCache() {
+        AccessibilityCache cache =
+                AccessibilityInteractionClient.getCache(mConnectionId);
+        if (cache == null) {
+            return false;
+        }
+        cache.clear();
+        return true;
+    }
+
+    /** Checks if {@code node} is in the cache.
+     * @param node the node to check.
+     * @return {@code true} if {@code node} is in the cache.
+     */
+    public boolean isNodeInCache(@NonNull AccessibilityNodeInfo node) {
+        AccessibilityCache cache =
+                AccessibilityInteractionClient.getCache(mConnectionId);
+        if (cache == null) {
+            return false;
+        }
+        return cache.isNodeInCache(node);
+    }
+
+    /** Returns {@code true} if the cache is enabled. */
+    public boolean isCacheEnabled() {
+        AccessibilityCache cache =
+                AccessibilityInteractionClient.getCache(mConnectionId);
+        if (cache == null) {
+            return false;
+        }
+        return cache.isEnabled();
+    }
+
     /** This is called when the system action list is changed. */
     public void onSystemActionsChanged() {
     }
@@ -2613,11 +2692,11 @@
                         mCallback.init(mConnectionId, windowToken);
                         mCallback.onServiceConnected();
                     } else {
+                        AccessibilityInteractionClient.getInstance(mContext)
+                                .clearCache(mConnectionId);
                         AccessibilityInteractionClient.getInstance(mContext).removeConnection(
                                 mConnectionId);
                         mConnectionId = AccessibilityInteractionClient.NO_ID;
-                        AccessibilityInteractionClient.getInstance(mContext)
-                                .clearCache(mConnectionId);
                         mCallback.init(AccessibilityInteractionClient.NO_ID, null);
                     }
                     return;
diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
index 93e6914..7d76bbf 100644
--- a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
+++ b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
@@ -124,6 +124,8 @@
 
     void setFocusAppearance(int strokeWidth, int color);
 
+    void setCacheEnabled(boolean enabled);
+
     oneway void logTrace(long timestamp, String where, long loggingTypes, String callingParams,
         int processId, long threadId, int callingUid, in Bundle serializedCallingStackInBundle);
 
diff --git a/core/java/android/accounts/ChooseAccountActivity.java b/core/java/android/accounts/ChooseAccountActivity.java
index bc7f4d6..6c8744f 100644
--- a/core/java/android/accounts/ChooseAccountActivity.java
+++ b/core/java/android/accounts/ChooseAccountActivity.java
@@ -148,7 +148,7 @@
             am.setAccountVisibility(account, mCallingPackage,
                 AccountManager.VISIBILITY_USER_MANAGED_VISIBLE);
         }
-        Log.d(TAG, "selected account " + account);
+        Log.d(TAG, "selected account " + account.toSafeString());
         Bundle bundle = new Bundle();
         bundle.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
         bundle.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
diff --git a/core/java/android/accounts/ChooseTypeAndAccountActivity.java b/core/java/android/accounts/ChooseTypeAndAccountActivity.java
index 2be88ab..2e9f73c 100644
--- a/core/java/android/accounts/ChooseTypeAndAccountActivity.java
+++ b/core/java/android/accounts/ChooseTypeAndAccountActivity.java
@@ -190,10 +190,6 @@
             mAccounts = getAcceptableAccountChoices(AccountManager.get(this));
         }
 
-        if (Log.isLoggable(TAG, Log.VERBOSE)) {
-            Log.v(TAG, "selected account name is " + mSelectedAccountName);
-        }
-
         mPossiblyVisibleAccounts = new ArrayList<>(mAccounts.size());
         for (Map.Entry<Account, Integer> entry : mAccounts.entrySet()) {
             if (AccountManager.VISIBILITY_NOT_VISIBLE != entry.getValue()) {
@@ -302,7 +298,7 @@
             if (data != null && data.getExtras() != null) data.getExtras().keySet();
             Bundle extras = data != null ? data.getExtras() : null;
             Log.v(TAG, "ChooseTypeAndAccountActivity.onActivityResult(reqCode=" + requestCode
-                    + ", resCode=" + resultCode + ", extras=" + extras + ")");
+                    + ", resCode=" + resultCode + ")");
         }
 
         // we got our result, so clear the fact that we had a pending request
@@ -424,8 +420,8 @@
     }
 
     private void onAccountSelected(Account account) {
-      Log.d(TAG, "selected account " + account);
-      setResultAndFinish(account.name, account.type);
+        Log.d(TAG, "selected account " + account.toSafeString());
+        setResultAndFinish(account.name, account.type);
     }
 
     private void setResultAndFinish(final String accountName, final String accountType) {
@@ -451,9 +447,8 @@
         setResult(Activity.RESULT_OK, new Intent().putExtras(bundle));
         if (Log.isLoggable(TAG, Log.VERBOSE)) {
             Log.v(TAG, "ChooseTypeAndAccountActivity.setResultAndFinish: selected account "
-                    + accountName + ", " + accountType);
+                    + account.toSafeString());
         }
-
         finish();
     }
 
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 11a2ede..cf2b7ac 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -6191,18 +6191,20 @@
     @Nullable
     public Uri getReferrer() {
         Intent intent = getIntent();
-        try {
-            Uri referrer = intent.getParcelableExtra(Intent.EXTRA_REFERRER);
-            if (referrer != null) {
-                return referrer;
+        if (intent != null) {
+            try {
+                Uri referrer = intent.getParcelableExtra(Intent.EXTRA_REFERRER);
+                if (referrer != null) {
+                    return referrer;
+                }
+                String referrerName = intent.getStringExtra(Intent.EXTRA_REFERRER_NAME);
+                if (referrerName != null) {
+                    return Uri.parse(referrerName);
+                }
+            } catch (BadParcelableException e) {
+                Log.w(TAG, "Cannot read referrer from intent;"
+                        + " intent extras contain unknown custom Parcelable objects");
             }
-            String referrerName = intent.getStringExtra(Intent.EXTRA_REFERRER_NAME);
-            if (referrerName != null) {
-                return Uri.parse(referrerName);
-            }
-        } catch (BadParcelableException e) {
-            Log.w(TAG, "Cannot read referrer from intent;"
-                    + " intent extras contain unknown custom Parcelable objects");
         }
         if (mReferrer != null) {
             return new Uri.Builder().scheme("android-app").authority(mReferrer).build();
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index d0096fd..5e5649f 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -337,7 +337,7 @@
     private static final String KEY_LAUNCHED_FROM_BUBBLE =
             "android.activity.launchTypeBubble";
 
-    /** See {@link #setSplashscreenStyle(int)}. */
+    /** See {@link #setSplashScreenStyle(int)}. */
     private static final String KEY_SPLASH_SCREEN_STYLE =
             "android.activity.splashScreenStyle";
 
@@ -380,6 +380,8 @@
     public static final int ANIM_OPEN_CROSS_PROFILE_APPS = 12;
     /** @hide */
     public static final int ANIM_REMOTE_ANIMATION = 13;
+    /** @hide */
+    public static final int ANIM_FROM_STYLE = 14;
 
     private String mPackageName;
     private Rect mLaunchBounds;
@@ -1391,20 +1393,27 @@
     }
 
     /**
-     * Sets the preferred splash screen style.
+     * Gets the style can be used for cold-launching an activity.
+     * @see #setSplashScreenStyle(int)
      * @hide
      */
-    public void setSplashscreenStyle(@SplashScreen.SplashScreenStyle int style) {
-        mSplashScreenStyle = style;
+    public @SplashScreen.SplashScreenStyle int getSplashScreenStyle() {
+        return mSplashScreenStyle;
     }
 
     /**
-     * Gets the preferred splash screen style from caller
-     * @hide
+     * Sets the preferred splash screen style of the opening activities. This only applies if the
+     * Activity or Process is not yet created.
+     * @param style Can be either {@link SplashScreen#SPLASH_SCREEN_STYLE_ICON} or
+     *              {@link SplashScreen#SPLASH_SCREEN_STYLE_EMPTY}
      */
-    @SplashScreen.SplashScreenStyle
-    public int getSplashScreenStyle() {
-        return mSplashScreenStyle;
+    @NonNull
+    public ActivityOptions setSplashScreenStyle(@SplashScreen.SplashScreenStyle int style) {
+        if (style == SplashScreen.SPLASH_SCREEN_STYLE_ICON
+                || style == SplashScreen.SPLASH_SCREEN_STYLE_EMPTY) {
+            mSplashScreenStyle = style;
+        }
+        return this;
     }
 
     /**
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index a8894dc..1778ea4 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -243,6 +243,7 @@
 import java.util.Objects;
 import java.util.TimeZone;
 import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.function.Consumer;
 
 /**
@@ -344,11 +345,9 @@
      */
     @UnsupportedAppUsage
     final ArrayMap<IBinder, ActivityClientRecord> mActivities = new ArrayMap<>();
-    /**
-     * Maps from activity token to local record of the activities that are preparing to be launched.
-     */
-    final Map<IBinder, ActivityClientRecord> mLaunchingActivities =
-            Collections.synchronizedMap(new ArrayMap<IBinder, ActivityClientRecord>());
+    /** Maps from activity token to the pending override configuration. */
+    @GuardedBy("mPendingOverrideConfigs")
+    private final ArrayMap<IBinder, Configuration> mPendingOverrideConfigs = new ArrayMap<>();
     /** The activities to be truly destroyed (not include relaunch). */
     final Map<IBinder, ClientTransactionItem> mActivitiesToBeDestroyed =
             Collections.synchronizedMap(new ArrayMap<IBinder, ClientTransactionItem>());
@@ -358,6 +357,7 @@
     // Number of activities that are currently visible on-screen.
     @UnsupportedAppUsage
     int mNumVisibleActivities = 0;
+    private final AtomicInteger mNumLaunchingActivities = new AtomicInteger();
     @GuardedBy("mAppThread")
     private int mLastProcessState = PROCESS_STATE_UNKNOWN;
     @GuardedBy("mAppThread")
@@ -555,10 +555,6 @@
         boolean hideForNow;
         Configuration createdConfig;
         Configuration overrideConfig;
-        // Used to save the last reported configuration from server side so that activity
-        // configuration transactions can always use the latest configuration.
-        @GuardedBy("this")
-        private Configuration mPendingOverrideConfig;
         // Used for consolidating configs before sending on to Activity.
         private Configuration tmpConfig = new Configuration();
         // Callback used for updating activity override config and camera compat control state.
@@ -3361,21 +3357,6 @@
     }
 
     @Override
-    public void addLaunchingActivity(IBinder token, ActivityClientRecord activity) {
-        mLaunchingActivities.put(token, activity);
-    }
-
-    @Override
-    public ActivityClientRecord getLaunchingActivity(IBinder token) {
-        return mLaunchingActivities.get(token);
-    }
-
-    @Override
-    public void removeLaunchingActivity(IBinder token) {
-        mLaunchingActivities.remove(token);
-    }
-
-    @Override
     public ActivityClientRecord getActivityClient(IBinder token) {
         return mActivities.get(token);
     }
@@ -3419,7 +3400,7 @@
             // Defer the top state for VM to avoid aggressive JIT compilation affecting activity
             // launch time.
             if (processState == ActivityManager.PROCESS_STATE_TOP
-                    && !mLaunchingActivities.isEmpty()) {
+                    && mNumLaunchingActivities.get() > 0) {
                 mPendingProcessState = processState;
                 mH.postDelayed(this::applyPendingProcessState, PENDING_TOP_PROCESS_STATE_TIMEOUT);
             } else {
@@ -3435,7 +3416,7 @@
         // Handle the pending configuration if the process state is changed from cached to
         // non-cached. Except the case where there is a launching activity because the
         // LaunchActivityItem will handle it.
-        if (wasCached && !isCachedProcessState() && mLaunchingActivities.isEmpty()) {
+        if (wasCached && !isCachedProcessState() && mNumLaunchingActivities.get() == 0) {
             final Configuration pendingConfig =
                     mConfigurationController.getPendingConfiguration(false /* clearPending */);
             if (pendingConfig == null) {
@@ -3473,6 +3454,11 @@
         }
     }
 
+    @Override
+    public void countLaunchingActivities(int num) {
+        mNumLaunchingActivities.getAndAdd(num);
+    }
+
     @UnsupportedAppUsage
     public final void sendActivityResult(
             IBinder token, String id, int requestCode,
@@ -6096,31 +6082,31 @@
     }
 
     /**
-     * Sets the supplied {@code overrideConfig} as pending for the {@code activityToken}. Calling
+     * Sets the supplied {@code overrideConfig} as pending for the {@code token}. Calling
      * this method prevents any calls to
      * {@link #handleActivityConfigurationChanged(ActivityClientRecord, Configuration, int)} from
      * processing any configurations older than {@code overrideConfig}.
      */
     @Override
-    public void updatePendingActivityConfiguration(ActivityClientRecord r,
-            Configuration overrideConfig) {
-        synchronized (r) {
-            if (r.mPendingOverrideConfig != null
-                    && !r.mPendingOverrideConfig.isOtherSeqNewer(overrideConfig)) {
+    public void updatePendingActivityConfiguration(IBinder token, Configuration overrideConfig) {
+        synchronized (mPendingOverrideConfigs) {
+            final Configuration pendingOverrideConfig = mPendingOverrideConfigs.get(token);
+            if (pendingOverrideConfig != null
+                    && !pendingOverrideConfig.isOtherSeqNewer(overrideConfig)) {
                 if (DEBUG_CONFIGURATION) {
-                    Slog.v(TAG, "Activity has newer configuration pending so drop this"
-                            + " transaction. overrideConfig=" + overrideConfig
-                            + " r.mPendingOverrideConfig=" + r.mPendingOverrideConfig);
+                    Slog.v(TAG, "Activity has newer configuration pending so this transaction will"
+                            + " be dropped. overrideConfig=" + overrideConfig
+                            + " pendingOverrideConfig=" + pendingOverrideConfig);
                 }
                 return;
             }
-            r.mPendingOverrideConfig = overrideConfig;
+            mPendingOverrideConfigs.put(token, overrideConfig);
         }
     }
 
     /**
      * Handle new activity configuration and/or move to a different display. This method is a noop
-     * if {@link #updatePendingActivityConfiguration(ActivityClientRecord, Configuration)} has been
+     * if {@link #updatePendingActivityConfiguration(IBinder, Configuration)} has been
      * called with a newer config than {@code overrideConfig}.
      *
      * @param r Target activity record.
@@ -6131,16 +6117,17 @@
     @Override
     public void handleActivityConfigurationChanged(ActivityClientRecord r,
             @NonNull Configuration overrideConfig, int displayId) {
-        synchronized (r) {
-            if (overrideConfig.isOtherSeqNewer(r.mPendingOverrideConfig)) {
+        synchronized (mPendingOverrideConfigs) {
+            final Configuration pendingOverrideConfig = mPendingOverrideConfigs.get(r.token);
+            if (overrideConfig.isOtherSeqNewer(pendingOverrideConfig)) {
                 if (DEBUG_CONFIGURATION) {
                     Slog.v(TAG, "Activity has newer configuration pending so drop this"
                             + " transaction. overrideConfig=" + overrideConfig
-                            + " r.mPendingOverrideConfig=" + r.mPendingOverrideConfig);
+                            + " pendingOverrideConfig=" + pendingOverrideConfig);
                 }
                 return;
             }
-            r.mPendingOverrideConfig = null;
+            mPendingOverrideConfigs.remove(r.token);
         }
 
         if (displayId == INVALID_DISPLAY) {
diff --git a/core/java/android/app/BroadcastOptions.java b/core/java/android/app/BroadcastOptions.java
index 3108d91..0bb6ffa 100644
--- a/core/java/android/app/BroadcastOptions.java
+++ b/core/java/android/app/BroadcastOptions.java
@@ -21,6 +21,11 @@
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
+import android.app.compat.CompatChanges;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.Disabled;
+import android.compat.annotation.EnabledSince;
+import android.content.Intent;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.PowerExemptionManager;
@@ -45,6 +50,35 @@
     private boolean mAllowBackgroundActivityStarts;
     private String[] mRequireAllOfPermissions;
     private String[] mRequireNoneOfPermissions;
+    private long mRequireCompatChangeId = CHANGE_INVALID;
+    private boolean mRequireCompatChangeEnabled = true;
+
+    /**
+     * Change ID which is invalid.
+     *
+     * @hide
+     */
+    public static final long CHANGE_INVALID = Long.MIN_VALUE;
+
+    /**
+     * Change ID which is always enabled, for testing purposes.
+     *
+     * @hide
+     */
+    @TestApi
+    @ChangeId
+    @EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.BASE)
+    public static final long CHANGE_ALWAYS_ENABLED = 209888056L;
+
+    /**
+     * Change ID which is always disabled, for testing purposes.
+     *
+     * @hide
+     */
+    @TestApi
+    @ChangeId
+    @Disabled
+    public static final long CHANGE_ALWAYS_DISABLED = 210856463L;
 
     /**
      * How long to temporarily put an app on the power allowlist when executing this broadcast
@@ -101,6 +135,18 @@
             "android:broadcast.requireNoneOfPermissions";
 
     /**
+     * Corresponds to {@link #setRequireCompatChange(long, boolean)}
+     */
+    private static final String KEY_REQUIRE_COMPAT_CHANGE_ID =
+            "android:broadcast.requireCompatChangeId";
+
+    /**
+     * Corresponds to {@link #setRequireCompatChange(long, boolean)}
+     */
+    private static final String KEY_REQUIRE_COMPAT_CHANGE_ENABLED =
+            "android:broadcast.requireCompatChangeEnabled";
+
+    /**
      * @hide
      * @deprecated Use {@link android.os.PowerExemptionManager#
      * TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED} instead.
@@ -150,6 +196,8 @@
                 false);
         mRequireAllOfPermissions = opts.getStringArray(KEY_REQUIRE_ALL_OF_PERMISSIONS);
         mRequireNoneOfPermissions = opts.getStringArray(KEY_REQUIRE_NONE_OF_PERMISSIONS);
+        mRequireCompatChangeId = opts.getLong(KEY_REQUIRE_COMPAT_CHANGE_ID, CHANGE_INVALID);
+        mRequireCompatChangeEnabled = opts.getBoolean(KEY_REQUIRE_COMPAT_CHANGE_ENABLED, true);
     }
 
     /**
@@ -270,16 +318,32 @@
      * Set the minimum target API level of receivers of the broadcast.  If an application
      * is targeting an API level less than this, the broadcast will not be delivered to
      * them.  This only applies to receivers declared in the app's AndroidManifest.xml.
+     *
+     * @deprecated to give developers the most flexibility during beta releases,
+     *             we strongly encourage using {@link ChangeId} instead of
+     *             target SDK checks; callers should use
+     *             {@link #setRequireCompatChange(long, boolean)} instead,
+     *             possibly combined with
+     *             {@link Intent#FLAG_RECEIVER_REGISTERED_ONLY}.
      * @hide
      */
+    @Deprecated
     public void setMinManifestReceiverApiLevel(int apiLevel) {
         mMinManifestReceiverApiLevel = apiLevel;
     }
 
     /**
      * Return {@link #setMinManifestReceiverApiLevel}.
+     *
+     * @deprecated to give developers the most flexibility during beta releases,
+     *             we strongly encourage using {@link ChangeId} instead of
+     *             target SDK checks; callers should use
+     *             {@link #setRequireCompatChange(long, boolean)} instead,
+     *             possibly combined with
+     *             {@link Intent#FLAG_RECEIVER_REGISTERED_ONLY}.
      * @hide
      */
+    @Deprecated
     public int getMinManifestReceiverApiLevel() {
         return mMinManifestReceiverApiLevel;
     }
@@ -288,20 +352,36 @@
      * Set the maximum target API level of receivers of the broadcast.  If an application
      * is targeting an API level greater than this, the broadcast will not be delivered to
      * them.  This only applies to receivers declared in the app's AndroidManifest.xml.
+     *
+     * @deprecated to give developers the most flexibility during beta releases,
+     *             we strongly encourage using {@link ChangeId} instead of
+     *             target SDK checks; callers should use
+     *             {@link #setRequireCompatChange(long, boolean)} instead,
+     *             possibly combined with
+     *             {@link Intent#FLAG_RECEIVER_REGISTERED_ONLY}.
      * @hide
      */
     @TestApi
     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    @Deprecated
     public void setMaxManifestReceiverApiLevel(int apiLevel) {
         mMaxManifestReceiverApiLevel = apiLevel;
     }
 
     /**
      * Return {@link #setMaxManifestReceiverApiLevel}.
+     *
+     * @deprecated to give developers the most flexibility during beta releases,
+     *             we strongly encourage using {@link ChangeId} instead of
+     *             target SDK checks; callers should use
+     *             {@link #setRequireCompatChange(long, boolean)} instead,
+     *             possibly combined with
+     *             {@link Intent#FLAG_RECEIVER_REGISTERED_ONLY}.
      * @hide
      */
     @TestApi
     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    @Deprecated
     public int getMaxManifestReceiverApiLevel() {
         return mMaxManifestReceiverApiLevel;
     }
@@ -379,6 +459,58 @@
     }
 
     /**
+     * When set, this broadcast will only be delivered to apps which have the
+     * given {@link ChangeId} in the given state.
+     * <p>
+     * Each {@link BroadcastOptions} instance supports only a single
+     * {@link ChangeId} requirement, so any subsequent calls will override any
+     * previously defined requirement.
+     * <p>
+     * This requirement applies to both manifest registered and runtime
+     * registered receivers.
+     *
+     * @param changeId the {@link ChangeId} to inspect
+     * @param enabled the required enabled state of the inspected
+     *            {@link ChangeId} for this broadcast to be delivered
+     * @see CompatChanges#isChangeEnabled
+     * @see #clearRequireCompatChange()
+     */
+    public void setRequireCompatChange(long changeId, boolean enabled) {
+        mRequireCompatChangeId = changeId;
+        mRequireCompatChangeEnabled = enabled;
+    }
+
+    /**
+     * Clear any previously defined requirement for this broadcast requested via
+     * {@link #setRequireCompatChange(long, boolean)}.
+     */
+    public void clearRequireCompatChange() {
+        mRequireCompatChangeId = CHANGE_INVALID;
+        mRequireCompatChangeEnabled = true;
+    }
+
+    /** {@hide} */
+    public long getRequireCompatChangeId() {
+        return mRequireCompatChangeId;
+    }
+
+    /**
+     * Test if the given app meets the {@link ChangeId} state required by this
+     * broadcast, if any.
+     *
+     * @hide
+     */
+    @TestApi
+    public boolean testRequireCompatChange(int uid) {
+        if (mRequireCompatChangeId != CHANGE_INVALID) {
+            return CompatChanges.isChangeEnabled(mRequireCompatChangeId,
+                    uid) == mRequireCompatChangeEnabled;
+        } else {
+            return true;
+        }
+    }
+
+    /**
      * Returns the created options as a Bundle, which can be passed to
      * {@link android.content.Context#sendBroadcast(android.content.Intent)
      * Context.sendBroadcast(Intent)} and related methods.
@@ -413,6 +545,10 @@
         if (mRequireNoneOfPermissions != null) {
             b.putStringArray(KEY_REQUIRE_NONE_OF_PERMISSIONS, mRequireNoneOfPermissions);
         }
+        if (mRequireCompatChangeId != CHANGE_INVALID) {
+            b.putLong(KEY_REQUIRE_COMPAT_CHANGE_ID, mRequireCompatChangeId);
+            b.putBoolean(KEY_REQUIRE_COMPAT_CHANGE_ENABLED, mRequireCompatChangeEnabled);
+        }
         return b.isEmpty() ? null : b;
     }
 }
diff --git a/core/java/android/app/ClientTransactionHandler.java b/core/java/android/app/ClientTransactionHandler.java
index c743f65..d365269 100644
--- a/core/java/android/app/ClientTransactionHandler.java
+++ b/core/java/android/app/ClientTransactionHandler.java
@@ -83,6 +83,9 @@
     /** Set current process state. */
     public abstract void updateProcessState(int processState, boolean fromIpc);
 
+    /** Count how many activities are launching. */
+    public abstract void countLaunchingActivities(int num);
+
     // Execute phase related logic and handlers. Methods here execute actual lifecycle transactions
     // and deliver callbacks.
 
@@ -139,7 +142,7 @@
     public abstract void performRestartActivity(@NonNull ActivityClientRecord r, boolean start);
 
     /** Set pending activity configuration in case it will be updated by other transaction item. */
-    public abstract void updatePendingActivityConfiguration(@NonNull ActivityClientRecord r,
+    public abstract void updatePendingActivityConfiguration(@NonNull IBinder token,
             Configuration overrideConfig);
 
     /** Deliver activity (override) configuration change. */
@@ -189,26 +192,6 @@
             FixedRotationAdjustments fixedRotationAdjustments);
 
     /**
-     * Add {@link ActivityClientRecord} that is preparing to be launched.
-     * @param token Activity token.
-     * @param activity An initialized instance of {@link ActivityClientRecord} to use during launch.
-     */
-    public abstract void addLaunchingActivity(IBinder token, ActivityClientRecord activity);
-
-    /**
-     * Get {@link ActivityClientRecord} that is preparing to be launched.
-     * @param token Activity token.
-     * @return An initialized instance of {@link ActivityClientRecord} to use during launch.
-     */
-    public abstract ActivityClientRecord getLaunchingActivity(IBinder token);
-
-    /**
-     * Remove {@link ActivityClientRecord} from the launching activity list.
-     * @param token Activity token.
-     */
-    public abstract void removeLaunchingActivity(IBinder token);
-
-    /**
      * Get {@link android.app.ActivityThread.ActivityClientRecord} instance that corresponds to the
      * provided token.
      */
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index f3e9f10..c895636 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1796,6 +1796,7 @@
                     && ((flags & Context.RECEIVER_NOT_EXPORTED) == 0)) {
                 flags = flags | Context.RECEIVER_EXPORTED;
             }
+
             final Intent intent = ActivityManager.getService().registerReceiverWithFeature(
                     mMainThread.getApplicationThread(), mBasePackageName, getAttributionTag(),
                     AppOpsManager.toReceiverId(receiver), rd, filter, broadcastPermission, userId,
@@ -1810,6 +1811,9 @@
             return intent;
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
+        } catch (WtfException e) {
+            Log.wtf(TAG, e.getMessage());
+            return null;
         }
     }
 
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 717e289..4aa2d2e 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -2199,8 +2199,11 @@
                     + conversationSendersToString(priorityConversationSenders)
                     + ",suppressedVisualEffects="
                     + suppressedEffectsToString(suppressedVisualEffects)
-                    + ",areChannelsBypassingDnd=" + (((state & STATE_CHANNELS_BYPASSING_DND) != 0)
-                        ? "true" : "false")
+                    + ",areChannelsBypassingDnd=" + (state == STATE_UNSET
+                        ? "unset"
+                        : ((state & STATE_CHANNELS_BYPASSING_DND) != 0)
+                                ? "true"
+                                : "false")
                     + "]";
         }
 
diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java
index ae578f5..64d3a9f 100644
--- a/core/java/android/app/StatusBarManager.java
+++ b/core/java/android/app/StatusBarManager.java
@@ -282,6 +282,33 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface RequestResult {}
 
+    /**
+     * Constant for {@link #setNavBarModeOverride(int)} indicating the default navbar mode.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int NAV_BAR_MODE_OVERRIDE_NONE = 0;
+
+    /**
+     * Constant for {@link #setNavBarModeOverride(int)} indicating kids navbar mode.
+     *
+     * <p>When used, back and home icons will change drawables and layout, recents will be hidden,
+     * and the navbar will remain visible when apps are in immersive mode.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int NAV_BAR_MODE_OVERRIDE_KIDS = 1;
+
+    /** @hide */
+    @IntDef(prefix = {"NAV_BAR_MODE_OVERRIDE_"}, value = {
+            NAV_BAR_MODE_OVERRIDE_NONE,
+            NAV_BAR_MODE_OVERRIDE_KIDS
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface NavBarModeOverride {}
+
     @UnsupportedAppUsage
     private Context mContext;
     private IStatusBarService mService;
@@ -687,6 +714,52 @@
         }
     }
 
+    /**
+     * Sets or removes the navigation bar mode override.
+     *
+     * @param navBarModeOverride the mode of the navigation bar override to be set.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.STATUS_BAR)
+    public void setNavBarModeOverride(@NavBarModeOverride int navBarModeOverride) {
+        if (navBarModeOverride != NAV_BAR_MODE_OVERRIDE_NONE
+                && navBarModeOverride != NAV_BAR_MODE_OVERRIDE_KIDS) {
+            throw new UnsupportedOperationException(
+                    "Supplied navBarModeOverride not supported: " + navBarModeOverride);
+        }
+
+        try {
+            final IStatusBarService svc = getService();
+            if (svc != null) {
+                svc.setNavBarModeOverride(navBarModeOverride);
+            }
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Gets the navigation bar mode override. Returns default value if no override is set.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.STATUS_BAR)
+    public @NavBarModeOverride int getNavBarModeOverride() {
+        int navBarModeOverride = NAV_BAR_MODE_OVERRIDE_NONE;
+        try {
+            final IStatusBarService svc = getService();
+            if (svc != null) {
+                navBarModeOverride = svc.getNavBarModeOverride();
+            }
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+        return navBarModeOverride;
+    }
+
     /** @hide */
     public static String windowStateToString(int state) {
         if (state == WINDOW_STATE_HIDING) return "WINDOW_STATE_HIDING";
diff --git a/core/java/android/app/WtfException.java b/core/java/android/app/WtfException.java
new file mode 100644
index 0000000..ba8dbef
--- /dev/null
+++ b/core/java/android/app/WtfException.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Exception meant to be thrown instead of calling Log.wtf() such that server side code can
+ * throw this exception, and it will carry across the binder to do client side logging.
+ * {@hide}
+ */
+public final class WtfException extends RuntimeException implements Parcelable {
+    public static final @android.annotation.NonNull
+            Creator<WtfException> CREATOR = new Creator<WtfException>() {
+                @Override
+                public WtfException createFromParcel(Parcel source) {
+                    return new WtfException(source.readString8());
+                }
+
+                @Override
+                public WtfException[] newArray(int size) {
+                    return new WtfException[size];
+                }
+            };
+
+    public WtfException(@android.annotation.NonNull String message) {
+        super(message);
+    }
+
+    /** {@hide} */
+    public static Throwable readFromParcel(Parcel in) {
+        final String msg = in.readString8();
+        return new WtfException(msg);
+    }
+
+    /** {@hide} */
+    public static void writeToParcel(Parcel out, Throwable t) {
+        out.writeString8(t.getMessage());
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@android.annotation.NonNull Parcel dest, int flags) {
+        dest.writeString8(getMessage());
+    }
+}
+
diff --git a/core/java/android/app/communal/CommunalManager.java b/core/java/android/app/communal/CommunalManager.java
index 22f07693..22bd9d1 100644
--- a/core/java/android/app/communal/CommunalManager.java
+++ b/core/java/android/app/communal/CommunalManager.java
@@ -23,9 +23,6 @@
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
-import android.compat.annotation.ChangeId;
-import android.compat.annotation.Disabled;
-import android.compat.annotation.Overridable;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.os.RemoteException;
@@ -46,31 +43,10 @@
     private final ICommunalManager mService;
     private final ArrayMap<CommunalModeListener, ICommunalModeListener> mCommunalModeListeners;
 
-    /**
-     * This change id is used to annotate packages which can run in communal mode by default,
-     * without requiring user opt-in.
-     *
-     * @hide
-     */
-    @ChangeId
-    @Overridable
-    @Disabled
-    public static final long ALLOW_COMMUNAL_MODE_BY_DEFAULT = 203673428L;
-
-    /**
-     * This change id is used to annotate packages which are allowed to run in communal mode.
-     *
-     * @hide
-     */
-    @ChangeId
-    @Overridable
-    @Disabled
-    public static final long ALLOW_COMMUNAL_MODE_WITH_USER_CONSENT = 200324021L;
-
     /** @hide */
     public CommunalManager(ICommunalManager service) {
         mService = service;
-        mCommunalModeListeners = new ArrayMap<CommunalModeListener, ICommunalModeListener>();
+        mCommunalModeListeners = new ArrayMap<>();
     }
 
     /**
diff --git a/core/java/android/app/compat/CompatChanges.java b/core/java/android/app/compat/CompatChanges.java
index 0d85fb9..d7b2ab4 100644
--- a/core/java/android/app/compat/CompatChanges.java
+++ b/core/java/android/app/compat/CompatChanges.java
@@ -22,8 +22,11 @@
 import android.compat.Compatibility;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.util.ArrayMap;
 
 import com.android.internal.compat.CompatibilityOverrideConfig;
+import com.android.internal.compat.CompatibilityOverridesByPackageConfig;
+import com.android.internal.compat.CompatibilityOverridesToRemoveByPackageConfig;
 import com.android.internal.compat.CompatibilityOverridesToRemoveConfig;
 
 import java.util.Map;
@@ -98,6 +101,31 @@
     }
 
     /**
+     * Equivalent to calling {@link #putPackageOverrides(String, Map)} on each entry in {@code
+     * packageNameToOverrides}, but the state of the compat config will be updated only once
+     * instead of for each package.
+     *
+     * @param packageNameToOverrides A map from package name to a map from change ID to the
+     *                               override applied for that package name and change ID.
+     */
+    @RequiresPermission(android.Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD)
+    public static void putAllPackageOverrides(
+            @NonNull Map<String, Map<Long, PackageOverride>> packageNameToOverrides) {
+        ArrayMap<String, CompatibilityOverrideConfig> packageNameToConfig = new ArrayMap<>();
+        for (String packageName : packageNameToOverrides.keySet()) {
+            packageNameToConfig.put(packageName,
+                    new CompatibilityOverrideConfig(packageNameToOverrides.get(packageName)));
+        }
+        CompatibilityOverridesByPackageConfig config = new CompatibilityOverridesByPackageConfig(
+                packageNameToConfig);
+        try {
+            QUERY_CACHE.getPlatformCompatService().putAllOverridesOnReleaseBuilds(config);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Associates app compat overrides with the given package and their respective change IDs.
      * This will check whether the caller is allowed to perform this operation on the given apk and
      * build. Only the installer package is allowed to set overrides on a non-debuggable final
@@ -123,6 +151,33 @@
     }
 
     /**
+     * Equivalent to calling {@link #removePackageOverrides(String, Set)} on each entry in {@code
+     * packageNameToOverridesToRemove}, but the state of the compat config will be updated only once
+     * instead of for each package.
+     *
+     * @param packageNameToOverridesToRemove A map from package name to a set of change IDs for
+     *                                       which to remove overrides for that package name.
+     */
+    @RequiresPermission(android.Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD)
+    public static void removeAllPackageOverrides(
+            @NonNull Map<String, Set<Long>> packageNameToOverridesToRemove) {
+        ArrayMap<String, CompatibilityOverridesToRemoveConfig> packageNameToConfig =
+                new ArrayMap<>();
+        for (String packageName : packageNameToOverridesToRemove.keySet()) {
+            packageNameToConfig.put(packageName,
+                    new CompatibilityOverridesToRemoveConfig(
+                            packageNameToOverridesToRemove.get(packageName)));
+        }
+        CompatibilityOverridesToRemoveByPackageConfig config =
+                new CompatibilityOverridesToRemoveByPackageConfig(packageNameToConfig);
+        try {
+            QUERY_CACHE.getPlatformCompatService().removeAllOverridesOnReleaseBuilds(config);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Removes app compat overrides for the given package. This will check whether the caller is
      * allowed to perform this operation on the given apk and build. Only the installer package is
      * allowed to clear overrides on a non-debuggable final build and a non-test apk.
diff --git a/core/java/android/app/prediction/AppPredictor.java b/core/java/android/app/prediction/AppPredictor.java
index fd1b9e3..db3a192 100644
--- a/core/java/android/app/prediction/AppPredictor.java
+++ b/core/java/android/app/prediction/AppPredictor.java
@@ -105,7 +105,7 @@
             e.rethrowAsRuntimeException();
         }
 
-        mCloseGuard.open("close");
+        mCloseGuard.open("AppPredictor.close");
     }
 
     /**
diff --git a/core/java/android/app/search/SearchSession.java b/core/java/android/app/search/SearchSession.java
index a5425a2..2cd1d96 100644
--- a/core/java/android/app/search/SearchSession.java
+++ b/core/java/android/app/search/SearchSession.java
@@ -106,7 +106,7 @@
             e.rethrowFromSystemServer();
         }
 
-        mCloseGuard.open("close");
+        mCloseGuard.open("SearchSession.close");
     }
 
     /**
diff --git a/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java b/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java
index 032b57e..5a3ad31 100644
--- a/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java
+++ b/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java
@@ -40,11 +40,9 @@
 
     @Override
     public void preExecute(android.app.ClientTransactionHandler client, IBinder token) {
-        final ActivityClientRecord r = getActivityClientRecord(client, token,
-                true /* includeLaunching */);
         // Notify the client of an upcoming change in the token configuration. This ensures that
         // batches of config change items only process the newest configuration.
-        client.updatePendingActivityConfiguration(r, mConfiguration);
+        client.updatePendingActivityConfiguration(token, mConfiguration);
     }
 
     @Override
diff --git a/core/java/android/app/servertransaction/ActivityTransactionItem.java b/core/java/android/app/servertransaction/ActivityTransactionItem.java
index 186f25d..6a6d76d 100644
--- a/core/java/android/app/servertransaction/ActivityTransactionItem.java
+++ b/core/java/android/app/servertransaction/ActivityTransactionItem.java
@@ -53,43 +53,23 @@
     public abstract void execute(@NonNull ClientTransactionHandler client,
             @NonNull ActivityClientRecord r, PendingTransactionActions pendingActions);
 
-    @NonNull ActivityClientRecord getActivityClientRecord(
-            @NonNull ClientTransactionHandler client, IBinder token) {
-        return getActivityClientRecord(client, token, false /* includeLaunching */);
-    }
-
     /**
      * 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 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 = 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");
-            }
-        }
+            @NonNull ClientTransactionHandler client, IBinder token) {
+        final ActivityClientRecord r = client.getActivityClient(token);
         if (r == null) {
             throw new IllegalArgumentException("Activity client record must not be null to execute "
                     + "transaction item");
         }
+        if (client.getActivity(token) == null) {
+            throw new IllegalArgumentException("Activity must not be null to execute "
+                    + "transaction item");
+        }
         return r;
     }
 }
diff --git a/core/java/android/app/servertransaction/LaunchActivityItem.java b/core/java/android/app/servertransaction/LaunchActivityItem.java
index 4de608b..0a2503c 100644
--- a/core/java/android/app/servertransaction/LaunchActivityItem.java
+++ b/core/java/android/app/servertransaction/LaunchActivityItem.java
@@ -82,12 +82,7 @@
 
     @Override
     public void preExecute(ClientTransactionHandler client, IBinder token) {
-        ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,
-                mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,
-                mPendingResults, mPendingNewIntents, mActivityOptions, mIsForward, mProfilerInfo,
-                client, mAssistToken, mFixedRotationAdjustments, mShareableActivityToken,
-                mLaunchedFromBubble);
-        client.addLaunchingActivity(token, r);
+        client.countLaunchingActivities(1);
         client.updateProcessState(mProcState, false);
         client.updatePendingConfiguration(mCurConfig);
         if (mActivityClientController != null) {
@@ -99,7 +94,11 @@
     public void execute(ClientTransactionHandler client, IBinder token,
             PendingTransactionActions pendingActions) {
         Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
-        ActivityClientRecord r = client.getLaunchingActivity(token);
+        ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,
+                mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,
+                mPendingResults, mPendingNewIntents, mActivityOptions, mIsForward, mProfilerInfo,
+                client, mAssistToken, mFixedRotationAdjustments, mShareableActivityToken,
+                mLaunchedFromBubble);
         client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
         Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
     }
@@ -107,7 +106,7 @@
     @Override
     public void postExecute(ClientTransactionHandler client, IBinder token,
             PendingTransactionActions pendingActions) {
-        client.removeLaunchingActivity(token);
+        client.countLaunchingActivities(-1);
     }
 
 
diff --git a/core/java/android/app/servertransaction/MoveToDisplayItem.java b/core/java/android/app/servertransaction/MoveToDisplayItem.java
index 4b8a347..2893ff2 100644
--- a/core/java/android/app/servertransaction/MoveToDisplayItem.java
+++ b/core/java/android/app/servertransaction/MoveToDisplayItem.java
@@ -40,11 +40,9 @@
 
     @Override
     public void preExecute(ClientTransactionHandler client, IBinder token) {
-        final ActivityClientRecord r = getActivityClientRecord(client, token,
-                true /* includeLaunching */);
         // Notify the client of an upcoming change in the token configuration. This ensures that
         // batches of config change items only process the newest configuration.
-        client.updatePendingActivityConfiguration(r, mConfiguration);
+        client.updatePendingActivityConfiguration(token, mConfiguration);
     }
 
     @Override
diff --git a/core/java/android/app/smartspace/SmartspaceSession.java b/core/java/android/app/smartspace/SmartspaceSession.java
index 9199581..b523be2 100644
--- a/core/java/android/app/smartspace/SmartspaceSession.java
+++ b/core/java/android/app/smartspace/SmartspaceSession.java
@@ -107,7 +107,7 @@
             e.rethrowFromSystemServer();
         }
 
-        mCloseGuard.open("close");
+        mCloseGuard.open("SmartspaceSession.close");
     }
 
     /**
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 2d1ecfb..9a0f02e 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -3064,6 +3064,9 @@
             BluetoothCsipSetCoordinator csipSetCoordinator =
                     new BluetoothCsipSetCoordinator(context, listener, this);
             return true;
+        } else if (profile == BluetoothProfile.LE_CALL_CONTROL) {
+            BluetoothLeCallControl tbs = new BluetoothLeCallControl(context, listener);
+            return true;
         } else {
             return false;
         }
@@ -3166,6 +3169,10 @@
                         (BluetoothCsipSetCoordinator) proxy;
                 csipSetCoordinator.close();
                 break;
+            case BluetoothProfile.LE_CALL_CONTROL:
+                BluetoothLeCallControl tbs = (BluetoothLeCallControl) proxy;
+                tbs.close();
+                break;
         }
     }
 
diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java
index fe8d1ba..b531829 100644
--- a/core/java/android/bluetooth/BluetoothGatt.java
+++ b/core/java/android/bluetooth/BluetoothGatt.java
@@ -87,7 +87,7 @@
     private static final int CONN_STATE_CLOSED = 4;
 
     private static final int WRITE_CHARACTERISTIC_MAX_RETRIES = 5;
-    private static final int WRITE_CHARACTERISTIC_TIME_TO_WAIT = 1000; // milliseconds
+    private static final int WRITE_CHARACTERISTIC_TIME_TO_WAIT = 10; // milliseconds
 
     private List<BluetoothGattService> mServices;
 
diff --git a/core/java/android/bluetooth/BluetoothLeBroadcastSourceInfo.java b/core/java/android/bluetooth/BluetoothLeBroadcastSourceInfo.java
new file mode 100644
index 0000000..cb47280
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothLeBroadcastSourceInfo.java
@@ -0,0 +1,788 @@
+/*
+ * 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.bluetooth;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * This class represents an LE Audio Broadcast Source and the associated information that is needed
+ * by Broadcast Audio Scan Service (BASS) residing on a Scan Delegator.
+ *
+ * <p>For example, the Scan Delegator on an LE Audio Broadcast Sink can use the information
+ * contained within an instance of this class to synchronize with an LE Audio Broadcast Source in
+ * order to listen to a Broadcast Audio Stream.
+ *
+ * <p>BroadcastAssistant has a BASS client which facilitates scanning and discovery of Broadcast
+ * Sources on behalf of say a Broadcast Sink. Upon successful discovery of one or more Broadcast
+ * sources, this information needs to be communicated to the BASS Server residing within the Scan
+ * Delegator on a Broadcast Sink. This is achieved using the Periodic Advertising Synchronization
+ * Transfer (PAST) procedure. This procedure uses information contained within an instance of this
+ * class.
+ *
+ * @hide
+ */
+public final class BluetoothLeBroadcastSourceInfo implements Parcelable {
+    private static final String TAG = "BluetoothLeBroadcastSourceInfo";
+    private static final boolean DBG = true;
+
+    /**
+     * Constants representing Broadcast Source address types
+     *
+     * @hide
+     */
+    @IntDef(
+            prefix = "LE_AUDIO_BROADCAST_SOURCE_ADDRESS_TYPE_",
+            value = {
+                LE_AUDIO_BROADCAST_SOURCE_ADDRESS_TYPE_PUBLIC,
+                LE_AUDIO_BROADCAST_SOURCE_ADDRESS_TYPE_RANDOM,
+                LE_AUDIO_BROADCAST_SOURCE_ADDRESS_TYPE_INVALID
+            })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface LeAudioBroadcastSourceAddressType {}
+
+    /**
+     * Represents a public address used by an LE Audio Broadcast Source
+     *
+     * @hide
+     */
+    public static final int LE_AUDIO_BROADCAST_SOURCE_ADDRESS_TYPE_PUBLIC = 0;
+
+    /**
+     * Represents a random address used by an LE Audio Broadcast Source
+     *
+     * @hide
+     */
+    public static final int LE_AUDIO_BROADCAST_SOURCE_ADDRESS_TYPE_RANDOM = 1;
+
+    /**
+     * Represents an invalid address used by an LE Audio Broadcast Seurce
+     *
+     * @hide
+     */
+    public static final int LE_AUDIO_BROADCAST_SOURCE_ADDRESS_TYPE_INVALID = 0xFFFF;
+
+    /**
+     * Periodic Advertising Synchronization state
+     *
+     * <p>Periodic Advertising (PA) enables the LE Audio Broadcast Assistant to discover broadcast
+     * audio streams as well as the audio stream configuration on behalf of an LE Audio Broadcast
+     * Sink. This information can then be transferred to the LE Audio Broadcast Sink using the
+     * Periodic Advertising Synchronizaton Transfer (PAST) procedure.
+     *
+     * @hide
+     */
+    @IntDef(
+            prefix = "LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_",
+            value = {
+                LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_IDLE,
+                LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_SYNCINFO_REQ,
+                LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_IN_SYNC,
+                LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_SYNC_FAIL,
+                LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_NO_PAST
+            })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface LeAudioBroadcastSinkPaSyncState {}
+
+    /**
+     * Indicates that the Broadcast Sink is not synchronized with the Periodic Advertisements (PA)
+     *
+     * @hide
+     */
+    public static final int LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_IDLE = 0;
+
+    /**
+     * Indicates that the Broadcast Sink requested the Broadcast Assistant to synchronize with the
+     * Periodic Advertisements (PA).
+     *
+     * <p>This is also known as scan delegation or scan offloading.
+     *
+     * @hide
+     */
+    public static final int LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_SYNCINFO_REQ = 1;
+
+    /**
+     * Indicates that the Broadcast Sink is synchronized with the Periodic Advertisements (PA).
+     *
+     * @hide
+     */
+    public static final int LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_IN_SYNC = 2;
+
+    /**
+     * Indicates that the Broadcast Sink was unable to synchronize with the Periodic Advertisements
+     * (PA).
+     *
+     * @hide
+     */
+    public static final int LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_SYNC_FAIL = 3;
+
+    /**
+     * Indicates that the Broadcast Sink should be synchronized with the Periodic Advertisements
+     * (PA) using the Periodic Advertisements Synchronization Transfert (PAST) procedure.
+     *
+     * @hide
+     */
+    public static final int LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_NO_PAST = 4;
+
+    /**
+     * Indicates that the Broadcast Sink synchornization state is invalid.
+     *
+     * @hide
+     */
+    public static final int LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_INVALID = 0xFFFF;
+
+    /** @hide */
+    @IntDef(
+            prefix = "LE_AUDIO_BROADCAST_SINK_AUDIO_SYNC_STATE_",
+            value = {
+                LE_AUDIO_BROADCAST_SINK_AUDIO_SYNC_STATE_NOT_SYNCHRONIZED,
+                LE_AUDIO_BROADCAST_SINK_AUDIO_SYNC_STATE_SYNCHRONIZED
+            })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface LeAudioBroadcastSinkAudioSyncState {}
+
+    /**
+     * Indicates that the Broadcast Sink is not synchronized with a Broadcast Audio Stream.
+     *
+     * @hide
+     */
+    public static final int LE_AUDIO_BROADCAST_SINK_AUDIO_SYNC_STATE_NOT_SYNCHRONIZED = 0;
+
+    /**
+     * Indicates that the Broadcast Sink is synchronized with a Broadcast Audio Stream.
+     *
+     * @hide
+     */
+    public static final int LE_AUDIO_BROADCAST_SINK_AUDIO_SYNC_STATE_SYNCHRONIZED = 1;
+
+    /**
+     * Indicates that the Broadcast Sink audio synchronization state is invalid.
+     *
+     * @hide
+     */
+    public static final int LE_AUDIO_BROADCAST_SINK_AUDIO_SYNC_STATE_INVALID = 0xFFFF;
+
+    /** @hide */
+    @IntDef(
+            prefix = "LE_AUDIO_BROADCAST_SINK_ENC_STATE_",
+            value = {
+                LE_AUDIO_BROADCAST_SINK_ENC_STATE_NOT_ENCRYPTED,
+                LE_AUDIO_BROADCAST_SINK_ENC_STATE_CODE_REQUIRED,
+                LE_AUDIO_BROADCAST_SINK_ENC_STATE_DECRYPTING,
+                LE_AUDIO_BROADCAST_SINK_ENC_STATE_BAD_CODE
+            })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface LeAudioBroadcastSinkEncryptionState {}
+
+    /**
+     * Indicates that the Broadcast Sink is synchronized with an unencrypted audio stream.
+     *
+     * @hide
+     */
+    public static final int LE_AUDIO_BROADCAST_SINK_ENC_STATE_NOT_ENCRYPTED = 0;
+
+    /**
+     * Indicates that the Broadcast Sink needs a Broadcast Code to synchronize with the audio
+     * stream.
+     *
+     * @hide
+     */
+    public static final int LE_AUDIO_BROADCAST_SINK_ENC_STATE_CODE_REQUIRED = 1;
+
+    /**
+     * Indicates that the Broadcast Sink is synchronized with an encrypted audio stream.
+     *
+     * @hide
+     */
+    public static final int LE_AUDIO_BROADCAST_SINK_ENC_STATE_DECRYPTING = 2;
+
+    /**
+     * Indicates that the Broadcast Sink is unable to decrypt an audio stream due to an incorrect
+     * Broadcast Code
+     *
+     * @hide
+     */
+    public static final int LE_AUDIO_BROADCAST_SINK_ENC_STATE_BAD_CODE = 3;
+
+    /**
+     * Indicates that the Broadcast Sink encryption state is invalid.
+     *
+     * @hide
+     */
+    public static final int LE_AUDIO_BROADCAST_SINK_ENC_STATE_INVALID = 0xFF;
+
+    /**
+     * Represents an invalid LE Audio Broadcast Source ID
+     *
+     * @hide
+     */
+    public static final byte LE_AUDIO_BROADCAST_SINK_INVALID_SOURCE_ID = (byte) 0x00;
+
+    /**
+     * Represents an invalid Broadcast ID of a Broadcast Source
+     *
+     * @hide
+     */
+    public static final int INVALID_BROADCAST_ID = 0xFFFFFF;
+
+    private byte mSourceId;
+    private @LeAudioBroadcastSourceAddressType int mSourceAddressType;
+    private BluetoothDevice mSourceDevice;
+    private byte mSourceAdvSid;
+    private int mBroadcastId;
+    private @LeAudioBroadcastSinkPaSyncState int mPaSyncState;
+    private @LeAudioBroadcastSinkEncryptionState int mEncryptionStatus;
+    private @LeAudioBroadcastSinkAudioSyncState int mAudioSyncState;
+    private byte[] mBadBroadcastCode;
+    private byte mNumSubGroups;
+    private Map<Integer, Integer> mSubgroupBisSyncState = new HashMap<Integer, Integer>();
+    private Map<Integer, byte[]> mSubgroupMetadata = new HashMap<Integer, byte[]>();
+
+    private String mBroadcastCode;
+    private static final int BIS_NO_PREF = 0xFFFFFFFF;
+    private static final int BROADCAST_CODE_SIZE = 16;
+
+    /**
+     * Constructor to create an Empty object of {@link BluetoothLeBroadcastSourceInfo } with the
+     * given Source Id.
+     *
+     * <p>This is mainly used to represent the Empty Broadcast Source entries
+     *
+     * @param sourceId Source Id for this Broadcast Source info object
+     * @hide
+     */
+    public BluetoothLeBroadcastSourceInfo(byte sourceId) {
+        mSourceId = sourceId;
+        mSourceAddressType = LE_AUDIO_BROADCAST_SOURCE_ADDRESS_TYPE_INVALID;
+        mSourceDevice = null;
+        mSourceAdvSid = (byte) 0x00;
+        mBroadcastId = INVALID_BROADCAST_ID;
+        mPaSyncState = LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_INVALID;
+        mAudioSyncState = LE_AUDIO_BROADCAST_SINK_AUDIO_SYNC_STATE_INVALID;
+        mEncryptionStatus = LE_AUDIO_BROADCAST_SINK_ENC_STATE_INVALID;
+        mBadBroadcastCode = null;
+        mNumSubGroups = 0;
+        mBroadcastCode = null;
+    }
+
+    /*package*/ BluetoothLeBroadcastSourceInfo(
+            byte sourceId,
+            @LeAudioBroadcastSourceAddressType int addressType,
+            @NonNull BluetoothDevice device,
+            byte advSid,
+            int broadcastId,
+            @LeAudioBroadcastSinkPaSyncState int paSyncstate,
+            @LeAudioBroadcastSinkEncryptionState int encryptionStatus,
+            @LeAudioBroadcastSinkAudioSyncState int audioSyncstate,
+            @Nullable byte[] badCode,
+            byte numSubGroups,
+            @NonNull Map<Integer, Integer> bisSyncState,
+            @Nullable Map<Integer, byte[]> subgroupMetadata,
+            @NonNull String broadcastCode) {
+        mSourceId = sourceId;
+        mSourceAddressType = addressType;
+        mSourceDevice = device;
+        mSourceAdvSid = advSid;
+        mBroadcastId = broadcastId;
+        mPaSyncState = paSyncstate;
+        mEncryptionStatus = encryptionStatus;
+        mAudioSyncState = audioSyncstate;
+
+        if (badCode != null && badCode.length != 0) {
+            mBadBroadcastCode = new byte[badCode.length];
+            System.arraycopy(badCode, 0, mBadBroadcastCode, 0, badCode.length);
+        }
+        mNumSubGroups = numSubGroups;
+        mSubgroupBisSyncState = new HashMap<Integer, Integer>(bisSyncState);
+        mSubgroupMetadata = new HashMap<Integer, byte[]>(subgroupMetadata);
+        mBroadcastCode = broadcastCode;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o instanceof BluetoothLeBroadcastSourceInfo) {
+            BluetoothLeBroadcastSourceInfo other = (BluetoothLeBroadcastSourceInfo) o;
+            return (other.mSourceId == mSourceId
+                    && other.mSourceAddressType == mSourceAddressType
+                    && other.mSourceDevice == mSourceDevice
+                    && other.mSourceAdvSid == mSourceAdvSid
+                    && other.mBroadcastId == mBroadcastId
+                    && other.mPaSyncState == mPaSyncState
+                    && other.mEncryptionStatus == mEncryptionStatus
+                    && other.mAudioSyncState == mAudioSyncState
+                    && Arrays.equals(other.mBadBroadcastCode, mBadBroadcastCode)
+                    && other.mNumSubGroups == mNumSubGroups
+                    && mSubgroupBisSyncState.equals(other.mSubgroupBisSyncState)
+                    && mSubgroupMetadata.equals(other.mSubgroupMetadata)
+                    && other.mBroadcastCode == mBroadcastCode);
+        }
+        return false;
+    }
+
+    /**
+     * Checks if an instance of {@link BluetoothLeBroadcastSourceInfo} is empty.
+     *
+     * @hide
+     */
+    public boolean isEmpty() {
+        boolean ret = false;
+        if (mSourceAddressType == LE_AUDIO_BROADCAST_SOURCE_ADDRESS_TYPE_INVALID
+                && mSourceDevice == null
+                && mSourceAdvSid == (byte) 0
+                && mPaSyncState == LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_INVALID
+                && mEncryptionStatus == LE_AUDIO_BROADCAST_SINK_ENC_STATE_INVALID
+                && mAudioSyncState == LE_AUDIO_BROADCAST_SINK_AUDIO_SYNC_STATE_INVALID
+                && mBadBroadcastCode == null
+                && mNumSubGroups == 0
+                && mSubgroupBisSyncState.size() == 0
+                && mSubgroupMetadata.size() == 0
+                && mBroadcastCode == null) {
+            ret = true;
+        }
+        return ret;
+    }
+
+    /**
+     * Compares an instance of {@link BluetoothLeBroadcastSourceInfo} with the provided instance.
+     *
+     * @hide
+     */
+    public boolean matches(BluetoothLeBroadcastSourceInfo srcInfo) {
+        boolean ret = false;
+        if (srcInfo == null) {
+            ret = false;
+        } else {
+            if (mSourceDevice == null) {
+                if (mSourceAdvSid == srcInfo.getAdvertisingSid()
+                        && mSourceAddressType == srcInfo.getAdvAddressType()) {
+                    ret = true;
+                }
+            } else {
+                if (mSourceDevice.equals(srcInfo.getSourceDevice())
+                        && mSourceAdvSid == srcInfo.getAdvertisingSid()
+                        && mSourceAddressType == srcInfo.getAdvAddressType()
+                        && mBroadcastId == srcInfo.getBroadcastId()) {
+                    ret = true;
+                }
+            }
+        }
+        return ret;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(
+                mSourceId,
+                mSourceAddressType,
+                mSourceDevice,
+                mSourceAdvSid,
+                mBroadcastId,
+                mPaSyncState,
+                mEncryptionStatus,
+                mAudioSyncState,
+                mBadBroadcastCode,
+                mNumSubGroups,
+                mSubgroupBisSyncState,
+                mSubgroupMetadata,
+                mBroadcastCode);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public String toString() {
+        return "{BluetoothLeBroadcastSourceInfo : mSourceId"
+                + mSourceId
+                + " addressType: "
+                + mSourceAddressType
+                + " sourceDevice: "
+                + mSourceDevice
+                + " mSourceAdvSid:"
+                + mSourceAdvSid
+                + " mBroadcastId:"
+                + mBroadcastId
+                + " mPaSyncState:"
+                + mPaSyncState
+                + " mEncryptionStatus:"
+                + mEncryptionStatus
+                + " mAudioSyncState:"
+                + mAudioSyncState
+                + " mBadBroadcastCode:"
+                + mBadBroadcastCode
+                + " mNumSubGroups:"
+                + mNumSubGroups
+                + " mSubgroupBisSyncState:"
+                + mSubgroupBisSyncState
+                + " mSubgroupMetadata:"
+                + mSubgroupMetadata
+                + " mBroadcastCode:"
+                + mBroadcastCode
+                + "}";
+    }
+
+    /**
+     * Get the Source Id
+     *
+     * @return byte representing the Source Id, {@link
+     *     #LE_AUDIO_BROADCAST_ASSISTANT_INVALID_SOURCE_ID} if invalid
+     * @hide
+     */
+    public byte getSourceId() {
+        return mSourceId;
+    }
+
+    /**
+     * Set the Source Id
+     *
+     * @param sourceId source Id
+     * @hide
+     */
+    public void setSourceId(byte sourceId) {
+        mSourceId = sourceId;
+    }
+
+    /**
+     * Set the Broadcast Source device
+     *
+     * @param sourceDevice the Broadcast Source BluetoothDevice
+     * @hide
+     */
+    public void setSourceDevice(@NonNull BluetoothDevice sourceDevice) {
+        mSourceDevice = sourceDevice;
+    }
+
+    /**
+     * Get the Broadcast Source BluetoothDevice
+     *
+     * @return Broadcast Source BluetoothDevice
+     * @hide
+     */
+    public @NonNull BluetoothDevice getSourceDevice() {
+        return mSourceDevice;
+    }
+
+    /**
+     * Set the address type of the Broadcast Source advertisements
+     *
+     * @hide
+     */
+    public void setAdvAddressType(@LeAudioBroadcastSourceAddressType int addressType) {
+        mSourceAddressType = addressType;
+    }
+
+    /**
+     * Get the address type used by advertisements from the Broadcast Source.
+     * BluetoothLeBroadcastSourceInfo Object
+     *
+     * @hide
+     */
+    @LeAudioBroadcastSourceAddressType
+    public int getAdvAddressType() {
+        return mSourceAddressType;
+    }
+
+    /**
+     * Set the advertising SID of the Broadcast Source advertisement.
+     *
+     * @param advSid advertising SID of the Broadcast Source
+     * @hide
+     */
+    public void setAdvertisingSid(byte advSid) {
+        mSourceAdvSid = advSid;
+    }
+
+    /**
+     * Get the advertising SID of the Broadcast Source advertisement.
+     *
+     * @return advertising SID of the Broadcast Source
+     * @hide
+     */
+    public byte getAdvertisingSid() {
+        return mSourceAdvSid;
+    }
+
+    /**
+     * Get the Broadcast ID of the Broadcast Source.
+     *
+     * @return broadcast ID
+     * @hide
+     */
+    public int getBroadcastId() {
+        return mBroadcastId;
+    }
+
+    /**
+     * Set the Periodic Advertising (PA) Sync State.
+     *
+     * @hide
+     */
+    /*package*/ void setPaSyncState(@LeAudioBroadcastSinkPaSyncState int paSyncState) {
+        mPaSyncState = paSyncState;
+    }
+
+    /**
+     * Get the Periodic Advertising (PA) Sync State
+     *
+     * @hide
+     */
+    public @LeAudioBroadcastSinkPaSyncState int getMetadataSyncState() {
+        return mPaSyncState;
+    }
+
+    /**
+     * Set the audio sync state
+     *
+     * @hide
+     */
+    /*package*/ void setAudioSyncState(@LeAudioBroadcastSinkAudioSyncState int audioSyncState) {
+        mAudioSyncState = audioSyncState;
+    }
+
+    /**
+     * Get the audio sync state
+     *
+     * @hide
+     */
+    public @LeAudioBroadcastSinkAudioSyncState int getAudioSyncState() {
+        return mAudioSyncState;
+    }
+
+    /**
+     * Set the encryption status
+     *
+     * @hide
+     */
+    /*package*/ void setEncryptionStatus(
+            @LeAudioBroadcastSinkEncryptionState int encryptionStatus) {
+        mEncryptionStatus = encryptionStatus;
+    }
+
+    /**
+     * Get the encryption status
+     *
+     * @hide
+     */
+    public @LeAudioBroadcastSinkEncryptionState int getEncryptionStatus() {
+        return mEncryptionStatus;
+    }
+
+    /**
+     * Get the incorrect broadcast code that the Scan delegator used to decrypt the Broadcast Audio
+     * Stream and failed.
+     *
+     * <p>This code is valid only if {@link #getEncryptionStatus} returns {@link
+     * #LE_AUDIO_BROADCAST_SINK_ENC_STATE_BAD_CODE}
+     *
+     * @return byte array containing bad broadcast value, null if the current encryption status is
+     *     not {@link #LE_AUDIO_BROADCAST_SINK_ENC_STATE_BAD_CODE}
+     * @hide
+     */
+    public @Nullable byte[] getBadBroadcastCode() {
+        return mBadBroadcastCode;
+    }
+
+    /**
+     * Get the number of subgroups.
+     *
+     * @return number of subgroups
+     * @hide
+     */
+    public byte getNumberOfSubGroups() {
+        return mNumSubGroups;
+    }
+
+    public @NonNull Map<Integer, Integer> getSubgroupBisSyncState() {
+        return mSubgroupBisSyncState;
+    }
+
+    public void setSubgroupBisSyncState(@NonNull Map<Integer, Integer> bisSyncState) {
+        mSubgroupBisSyncState = new HashMap<Integer, Integer>(bisSyncState);
+    }
+
+    /*package*/ void setBroadcastCode(@NonNull String broadcastCode) {
+        mBroadcastCode = broadcastCode;
+    }
+
+    /**
+     * Get the broadcast code
+     *
+     * @return
+     * @hide
+     */
+    public @NonNull String getBroadcastCode() {
+        return mBroadcastCode;
+    }
+
+    /**
+     * Set the broadcast ID
+     *
+     * @param broadcastId broadcast ID of the Broadcast Source
+     * @hide
+     */
+    public void setBroadcastId(int broadcastId) {
+        mBroadcastId = broadcastId;
+    }
+
+    private void writeSubgroupBisSyncStateToParcel(
+            @NonNull Parcel dest, @NonNull Map<Integer, Integer> subgroupBisSyncState) {
+        dest.writeInt(subgroupBisSyncState.size());
+        for (Map.Entry<Integer, Integer> entry : subgroupBisSyncState.entrySet()) {
+            dest.writeInt(entry.getKey());
+            dest.writeInt(entry.getValue());
+        }
+    }
+
+    private static void readSubgroupBisSyncStateFromParcel(
+            @NonNull Parcel in, @NonNull Map<Integer, Integer> subgroupBisSyncState) {
+        int size = in.readInt();
+
+        for (int i = 0; i < size; i++) {
+            Integer key = in.readInt();
+            Integer value = in.readInt();
+            subgroupBisSyncState.put(key, value);
+        }
+    }
+
+    private void writeSubgroupMetadataToParcel(
+            @NonNull Parcel dest, @Nullable Map<Integer, byte[]> subgroupMetadata) {
+        if (subgroupMetadata == null) {
+            dest.writeInt(0);
+            return;
+        }
+
+        dest.writeInt(subgroupMetadata.size());
+        for (Map.Entry<Integer, byte[]> entry : subgroupMetadata.entrySet()) {
+            dest.writeInt(entry.getKey());
+            byte[] metadata = entry.getValue();
+            if (metadata != null) {
+                dest.writeInt(metadata.length);
+                dest.writeByteArray(metadata);
+            }
+        }
+    }
+
+    private static void readSubgroupMetadataFromParcel(
+            @NonNull Parcel in, @NonNull Map<Integer, byte[]> subgroupMetadata) {
+        int size = in.readInt();
+
+        for (int i = 0; i < size; i++) {
+            Integer key = in.readInt();
+            Integer metaDataLen = in.readInt();
+            byte[] metadata = null;
+            if (metaDataLen != 0) {
+                metadata = new byte[metaDataLen];
+                in.readByteArray(metadata);
+            }
+            subgroupMetadata.put(key, metadata);
+        }
+    }
+
+    public static final @NonNull Parcelable.Creator<BluetoothLeBroadcastSourceInfo> CREATOR =
+            new Parcelable.Creator<BluetoothLeBroadcastSourceInfo>() {
+                public @NonNull BluetoothLeBroadcastSourceInfo createFromParcel(
+                        @NonNull Parcel in) {
+                    final byte sourceId = in.readByte();
+                    final int sourceAddressType = in.readInt();
+                    final BluetoothDevice sourceDevice =
+                            in.readTypedObject(BluetoothDevice.CREATOR);
+                    final byte sourceAdvSid = in.readByte();
+                    final int broadcastId = in.readInt();
+                    final int paSyncState = in.readInt();
+                    final int audioSyncState = in.readInt();
+                    final int encryptionStatus = in.readInt();
+                    final int badBroadcastLen = in.readInt();
+                    byte[] badBroadcastCode = null;
+
+                    if (badBroadcastLen > 0) {
+                        badBroadcastCode = new byte[badBroadcastLen];
+                        in.readByteArray(badBroadcastCode);
+                    }
+                    final byte numSubGroups = in.readByte();
+                    final String broadcastCode = in.readString();
+                    Map<Integer, Integer> subgroupBisSyncState = new HashMap<Integer, Integer>();
+                    readSubgroupBisSyncStateFromParcel(in, subgroupBisSyncState);
+                    Map<Integer, byte[]> subgroupMetadata = new HashMap<Integer, byte[]>();
+                    readSubgroupMetadataFromParcel(in, subgroupMetadata);
+
+                    BluetoothLeBroadcastSourceInfo srcInfo =
+                            new BluetoothLeBroadcastSourceInfo(
+                                    sourceId,
+                                    sourceAddressType,
+                                    sourceDevice,
+                                    sourceAdvSid,
+                                    broadcastId,
+                                    paSyncState,
+                                    encryptionStatus,
+                                    audioSyncState,
+                                    badBroadcastCode,
+                                    numSubGroups,
+                                    subgroupBisSyncState,
+                                    subgroupMetadata,
+                                    broadcastCode);
+                    return srcInfo;
+                }
+
+                public @NonNull BluetoothLeBroadcastSourceInfo[] newArray(int size) {
+                    return new BluetoothLeBroadcastSourceInfo[size];
+                }
+            };
+
+    @Override
+    public void writeToParcel(@NonNull Parcel out, int flags) {
+        out.writeByte(mSourceId);
+        out.writeInt(mSourceAddressType);
+        out.writeTypedObject(mSourceDevice, 0);
+        out.writeByte(mSourceAdvSid);
+        out.writeInt(mBroadcastId);
+        out.writeInt(mPaSyncState);
+        out.writeInt(mAudioSyncState);
+        out.writeInt(mEncryptionStatus);
+
+        if (mBadBroadcastCode != null) {
+            out.writeInt(mBadBroadcastCode.length);
+            out.writeByteArray(mBadBroadcastCode);
+        } else {
+            // zero indicates that there is no "bad broadcast code"
+            out.writeInt(0);
+        }
+        out.writeByte(mNumSubGroups);
+        out.writeString(mBroadcastCode);
+        writeSubgroupBisSyncStateToParcel(out, mSubgroupBisSyncState);
+        writeSubgroupMetadataToParcel(out, mSubgroupMetadata);
+    }
+
+    private static void log(@NonNull String msg) {
+        if (DBG) {
+            Log.d(TAG, msg);
+        }
+    }
+}
+;
diff --git a/core/java/android/bluetooth/BluetoothLeCall.java b/core/java/android/bluetooth/BluetoothLeCall.java
new file mode 100644
index 0000000..fb7789d
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothLeCall.java
@@ -0,0 +1,285 @@
+/*
+ * Copyright 2021 HIMSA II K/S - www.himsa.com.
+ * Represented by EHIMA - www.ehima.com
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.bluetooth;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.ParcelUuid;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
+import java.util.UUID;
+
+/**
+ * Representation of Call
+ *
+ * @hide
+ */
+public final class BluetoothLeCall implements Parcelable {
+
+    /** @hide */
+    @IntDef(prefix = "STATE_", value = {
+            STATE_INCOMING,
+            STATE_DIALING,
+            STATE_ALERTING,
+            STATE_ACTIVE,
+            STATE_LOCALLY_HELD,
+            STATE_REMOTELY_HELD,
+            STATE_LOCALLY_AND_REMOTELY_HELD
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface State {
+    }
+
+    /**
+     * A remote party is calling (incoming call).
+     *
+     * @hide
+     */
+    public static final int STATE_INCOMING = 0x00;
+
+    /**
+     * The process to call the remote party has started but the remote party is not
+     * being alerted (outgoing call).
+     *
+     * @hide
+     */
+    public static final int STATE_DIALING = 0x01;
+
+    /**
+     * A remote party is being alerted (outgoing call).
+     *
+     * @hide
+     */
+    public static final int STATE_ALERTING = 0x02;
+
+    /**
+     * The call is in an active conversation.
+     *
+     * @hide
+     */
+    public static final int STATE_ACTIVE = 0x03;
+
+    /**
+     * The call is connected but held locally. “Locally Held” implies that either
+     * the server or the client can affect the state.
+     *
+     * @hide
+     */
+    public static final int STATE_LOCALLY_HELD = 0x04;
+
+    /**
+     * The call is connected but held remotely. “Remotely Held” means that the state
+     * is controlled by the remote party of a call.
+     *
+     * @hide
+     */
+    public static final int STATE_REMOTELY_HELD = 0x05;
+
+    /**
+     * The call is connected but held both locally and remotely.
+     *
+     * @hide
+     */
+    public static final int STATE_LOCALLY_AND_REMOTELY_HELD = 0x06;
+
+    /**
+     * Whether the call direction is outgoing.
+     *
+     * @hide
+     */
+    public static final int FLAG_OUTGOING_CALL = 0x00000001;
+
+    /**
+     * Whether the call URI and Friendly Name are withheld by server.
+     *
+     * @hide
+     */
+    public static final int FLAG_WITHHELD_BY_SERVER = 0x00000002;
+
+    /**
+     * Whether the call URI and Friendly Name are withheld by network.
+     *
+     * @hide
+     */
+    public static final int FLAG_WITHHELD_BY_NETWORK = 0x00000004;
+
+    /** Unique UUID that identifies this call */
+    private UUID mUuid;
+
+    /** Remote Caller URI */
+    private String mUri;
+
+    /** Caller friendly name */
+    private String mFriendlyName;
+
+    /** Call state */
+    private @State int mState;
+
+    /** Call flags */
+    private int mCallFlags;
+
+    /** @hide */
+    public BluetoothLeCall(@NonNull BluetoothLeCall that) {
+        mUuid = new UUID(that.getUuid().getMostSignificantBits(),
+                that.getUuid().getLeastSignificantBits());
+        mUri = that.mUri;
+        mFriendlyName = that.mFriendlyName;
+        mState = that.mState;
+        mCallFlags = that.mCallFlags;
+    }
+
+    /** @hide */
+    public BluetoothLeCall(@NonNull UUID uuid, @NonNull String uri, @NonNull String friendlyName,
+            @State int state, int callFlags) {
+        mUuid = uuid;
+        mUri = uri;
+        mFriendlyName = friendlyName;
+        mState = state;
+        mCallFlags = callFlags;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o)
+            return true;
+        if (o == null || getClass() != o.getClass())
+            return false;
+        BluetoothLeCall that = (BluetoothLeCall) o;
+        return mUuid.equals(that.mUuid) && mUri.equals(that.mUri)
+                && mFriendlyName.equals(that.mFriendlyName) && mState == that.mState
+                && mCallFlags == that.mCallFlags;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mUuid, mUri, mFriendlyName, mState, mCallFlags);
+    }
+
+    /**
+     * Returns a string representation of this BluetoothLeCall.
+     *
+     * <p>
+     * Currently this is the UUID.
+     *
+     * @return string representation of this BluetoothLeCall
+     */
+    @Override
+    public String toString() {
+        return mUuid.toString();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel out, int flags) {
+        out.writeParcelable(new ParcelUuid(mUuid), 0);
+        out.writeString(mUri);
+        out.writeString(mFriendlyName);
+        out.writeInt(mState);
+        out.writeInt(mCallFlags);
+    }
+
+    public static final @android.annotation.NonNull Parcelable.Creator<BluetoothLeCall> CREATOR =
+    						    new Parcelable.Creator<BluetoothLeCall>() {
+        public BluetoothLeCall createFromParcel(Parcel in) {
+            return new BluetoothLeCall(in);
+        }
+
+        public BluetoothLeCall[] newArray(int size) {
+            return new BluetoothLeCall[size];
+        }
+    };
+
+    private BluetoothLeCall(Parcel in) {
+        mUuid = ((ParcelUuid) in.readParcelable(null)).getUuid();
+        mUri = in.readString();
+        mFriendlyName = in.readString();
+        mState = in.readInt();
+        mCallFlags = in.readInt();
+    }
+
+    /**
+     * Returns an UUID of this BluetoothLeCall.
+     *
+     * <p>
+     * An UUID is unique identifier of a BluetoothLeCall.
+     *
+     * @return UUID of this BluetoothLeCall
+     * @hide
+     */
+    public @NonNull UUID getUuid() {
+        return mUuid;
+    }
+
+    /**
+     * Returns a URI of the remote party of this BluetoothLeCall.
+     *
+     * @return string representation of this BluetoothLeCall
+     * @hide
+     */
+    public @NonNull String getUri() {
+        return mUri;
+    }
+
+    /**
+     * Returns a friendly name of the call.
+     *
+     * @return friendly name representation of this BluetoothLeCall
+     * @hide
+     */
+    public @NonNull String getFriendlyName() {
+        return mFriendlyName;
+    }
+
+    /**
+     * Returns the call state.
+     *
+     * @return the state of this BluetoothLeCall
+     * @hide
+     */
+    public @State int getState() {
+        return mState;
+    }
+
+    /**
+     * Returns the call flags.
+     *
+     * @return call flags
+     * @hide
+     */
+    public int getCallFlags() {
+        return mCallFlags;
+    }
+
+    /**
+     * Whether the call direction is incoming.
+     *
+     * @return true if incoming call, false otherwise
+     * @hide
+     */
+    public boolean isIncomingCall() {
+        return (mCallFlags & FLAG_OUTGOING_CALL) == 0;
+    }
+}
diff --git a/core/java/android/bluetooth/BluetoothLeCallControl.java b/core/java/android/bluetooth/BluetoothLeCallControl.java
new file mode 100644
index 0000000..5283e08
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothLeCallControl.java
@@ -0,0 +1,911 @@
+/*
+ * Copyright 2019 HIMSA II K/S - www.himsa.com.
+ * Represented by EHIMA - www.ehima.com
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.bluetooth;
+
+import android.Manifest;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.ParcelUuid;
+import android.os.RemoteException;
+import android.util.Log;
+import android.annotation.SuppressLint;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+import java.util.concurrent.Executor;
+
+/**
+ * This class provides the APIs to control the Call Control profile.
+ *
+ * <p>
+ * This class provides Bluetooth Telephone Bearer Service functionality,
+ * allowing applications to expose a GATT Service based interface to control the
+ * state of the calls by remote devices such as LE audio devices.
+ *
+ * <p>
+ * BluetoothLeCallControl is a proxy object for controlling the Bluetooth Telephone Bearer
+ * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get the
+ * BluetoothLeCallControl proxy object.
+ *
+ * @hide
+ */
+public final class BluetoothLeCallControl implements BluetoothProfile {
+    private static final String TAG = "BluetoothLeCallControl";
+    private static final boolean DBG = true;
+    private static final boolean VDBG = false;
+
+    /** @hide */
+    @IntDef(prefix = "RESULT_", value = {
+            RESULT_SUCCESS,
+            RESULT_ERROR_UNKNOWN_CALL_ID,
+            RESULT_ERROR_INVALID_URI,
+            RESULT_ERROR_APPLICATION
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Result {
+    }
+
+    /**
+     * Opcode write was successful.
+     *
+     * @hide
+     */
+    public static final int RESULT_SUCCESS = 0;
+
+    /**
+     * Unknown call Id has been used in the operation.
+     *
+     * @hide
+     */
+    public static final int RESULT_ERROR_UNKNOWN_CALL_ID = 1;
+
+    /**
+     * The URI provided in {@link Callback#onPlaceCallRequest} is invalid.
+     *
+     * @hide
+     */
+    public static final int RESULT_ERROR_INVALID_URI = 2;
+
+    /**
+     * Application internal error.
+     *
+     * @hide
+     */
+    public static final int RESULT_ERROR_APPLICATION = 3;
+
+    /** @hide */
+    @IntDef(prefix = "TERMINATION_REASON_", value = {
+            TERMINATION_REASON_INVALID_URI,
+            TERMINATION_REASON_FAIL,
+            TERMINATION_REASON_REMOTE_HANGUP,
+            TERMINATION_REASON_SERVER_HANGUP,
+            TERMINATION_REASON_LINE_BUSY,
+            TERMINATION_REASON_NETWORK_CONGESTION,
+            TERMINATION_REASON_CLIENT_HANGUP,
+            TERMINATION_REASON_NO_SERVICE,
+            TERMINATION_REASON_NO_ANSWER
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface TerminationReason {
+    }
+
+    /**
+     * Remote Caller ID value used to place a call was formed improperly.
+     *
+     * @hide
+     */
+    public static final int TERMINATION_REASON_INVALID_URI = 0x00;
+
+    /**
+     * Call fail.
+     *
+     * @hide
+     */
+    public static final int TERMINATION_REASON_FAIL = 0x01;
+
+    /**
+     * Remote party ended call.
+     *
+     * @hide
+     */
+    public static final int TERMINATION_REASON_REMOTE_HANGUP = 0x02;
+
+    /**
+     * Call ended from the server.
+     *
+     * @hide
+     */
+    public static final int TERMINATION_REASON_SERVER_HANGUP = 0x03;
+
+    /**
+     * Line busy.
+     *
+     * @hide
+     */
+    public static final int TERMINATION_REASON_LINE_BUSY = 0x04;
+
+    /**
+     * Network congestion.
+     *
+     * @hide
+     */
+    public static final int TERMINATION_REASON_NETWORK_CONGESTION = 0x05;
+
+    /**
+     * Client terminated.
+     *
+     * @hide
+     */
+    public static final int TERMINATION_REASON_CLIENT_HANGUP = 0x06;
+
+    /**
+     * No service.
+     *
+     * @hide
+     */
+    public static final int TERMINATION_REASON_NO_SERVICE = 0x07;
+
+    /**
+     * No answer.
+     *
+     * @hide
+     */
+    public static final int TERMINATION_REASON_NO_ANSWER = 0x08;
+
+    /*
+     * Flag indicating support for hold/unhold call feature.
+     *
+     * @hide
+     */
+    public static final int CAPABILITY_HOLD_CALL = 0x00000001;
+
+    /**
+     * Flag indicating support for joining calls feature.
+     *
+     * @hide
+     */
+    public static final int CAPABILITY_JOIN_CALLS = 0x00000002;
+
+    private static final int MESSAGE_TBS_SERVICE_CONNECTED = 102;
+    private static final int MESSAGE_TBS_SERVICE_DISCONNECTED = 103;
+
+    private static final int REG_TIMEOUT = 10000;
+
+    /**
+     * The template class is used to call callback functions on events from the TBS
+     * server. Callback functions are wrapped in this class and registered to the
+     * Android system during app registration.
+     *
+     * @hide
+     */
+    public abstract static class Callback {
+
+        private static final String TAG = "BluetoothLeCallControl.Callback";
+
+        /**
+         * Called when a remote client requested to accept the call.
+         *
+         * <p>
+         * An application must call {@link BluetoothLeCallControl#requestResult} to complete the
+         * request.
+         *
+         * @param requestId The Id of the request
+         * @param callId    The call Id requested to be accepted
+         * @hide
+         */
+        public abstract void onAcceptCall(int requestId, @NonNull UUID callId);
+
+        /**
+         * A remote client has requested to terminate the call.
+         *
+         * <p>
+         * An application must call {@link BluetoothLeCallControl#requestResult} to complete the
+         * request.
+         *
+         * @param requestId The Id of the request
+         * @param callId    The call Id requested to terminate
+         * @hide
+         */
+        public abstract void onTerminateCall(int requestId, @NonNull UUID callId);
+
+        /**
+         * A remote client has requested to hold the call.
+         *
+         * <p>
+         * An application must call {@link BluetoothLeCallControl#requestResult} to complete the
+         * request.
+         *
+         * @param requestId The Id of the request
+         * @param callId    The call Id requested to be put on hold
+         * @hide
+         */
+        public void onHoldCall(int requestId, @NonNull UUID callId) {
+            Log.e(TAG, "onHoldCall: unimplemented, however CAPABILITY_HOLD_CALL is set!");
+        }
+
+        /**
+         * A remote client has requested to unhold the call.
+         *
+         * <p>
+         * An application must call {@link BluetoothLeCallControl#requestResult} to complete the
+         * request.
+         *
+         * @param requestId The Id of the request
+         * @param callId    The call Id requested to unhold
+         * @hide
+         */
+        public void onUnholdCall(int requestId, @NonNull UUID callId) {
+            Log.e(TAG, "onUnholdCall: unimplemented, however CAPABILITY_HOLD_CALL is set!");
+        }
+
+        /**
+         * A remote client has requested to place a call.
+         *
+         * <p>
+         * An application must call {@link BluetoothLeCallControl#requestResult} to complete the
+         * request.
+         *
+         * @param requestId The Id of the request
+         * @param callId    The Id to be assigned for the new call
+         * @param uri       The caller URI requested
+         * @hide
+         */
+        public abstract void onPlaceCall(int requestId, @NonNull UUID callId, @NonNull String uri);
+
+        /**
+         * A remote client has requested to join the calls.
+         *
+         * <p>
+         * An application must call {@link BluetoothLeCallControl#requestResult} to complete the
+         * request.
+         *
+         * @param requestId The Id of the request
+         * @param callIds   The call Id list requested to join
+         * @hide
+         */
+        public void onJoinCalls(int requestId, @NonNull List<UUID> callIds) {
+            Log.e(TAG, "onJoinCalls: unimplemented, however CAPABILITY_JOIN_CALLS is set!");
+        }
+    }
+
+    private class CallbackWrapper extends IBluetoothLeCallControlCallback.Stub {
+
+        private final Executor mExecutor;
+        private final Callback mCallback;
+
+        CallbackWrapper(Executor executor, Callback callback) {
+            mExecutor = executor;
+            mCallback = callback;
+        }
+
+        @Override
+        public void onBearerRegistered(int ccid) {
+            synchronized (mServerIfLock) {
+                if (mCallback != null) {
+                    mCcid = ccid;
+                    mServerIfLock.notifyAll();
+                } else {
+                    // registration timeout
+                    Log.e(TAG, "onBearerRegistered: mCallback is null");
+                }
+            }
+        }
+
+        @Override
+        public void onAcceptCall(int requestId, ParcelUuid uuid) {
+            final long identityToken = Binder.clearCallingIdentity();
+            try {
+                mExecutor.execute(() -> mCallback.onAcceptCall(requestId, uuid.getUuid()));
+            } finally {
+                Binder.restoreCallingIdentity(identityToken);
+            }
+        }
+
+        @Override
+        public void onTerminateCall(int requestId, ParcelUuid uuid) {
+            final long identityToken = Binder.clearCallingIdentity();
+            try {
+                mExecutor.execute(() -> mCallback.onTerminateCall(requestId, uuid.getUuid()));
+            } finally {
+                Binder.restoreCallingIdentity(identityToken);
+            }
+        }
+
+        @Override
+        public void onHoldCall(int requestId, ParcelUuid uuid) {
+            final long identityToken = Binder.clearCallingIdentity();
+            try {
+                mExecutor.execute(() -> mCallback.onHoldCall(requestId, uuid.getUuid()));
+            } finally {
+                Binder.restoreCallingIdentity(identityToken);
+            }
+        }
+
+        @Override
+        public void onUnholdCall(int requestId, ParcelUuid uuid) {
+            final long identityToken = Binder.clearCallingIdentity();
+            try {
+                mExecutor.execute(() -> mCallback.onUnholdCall(requestId, uuid.getUuid()));
+            } finally {
+                Binder.restoreCallingIdentity(identityToken);
+            }
+        }
+
+        @Override
+        public void onPlaceCall(int requestId, ParcelUuid uuid, String uri) {
+            final long identityToken = Binder.clearCallingIdentity();
+            try {
+                mExecutor.execute(() -> mCallback.onPlaceCall(requestId, uuid.getUuid(), uri));
+            } finally {
+                Binder.restoreCallingIdentity(identityToken);
+            }
+        }
+
+        @Override
+        public void onJoinCalls(int requestId, List<ParcelUuid> parcelUuids) {
+            List<UUID> uuids = new ArrayList<>();
+            for (ParcelUuid parcelUuid : parcelUuids) {
+                uuids.add(parcelUuid.getUuid());
+            }
+
+            final long identityToken = Binder.clearCallingIdentity();
+            try {
+                mExecutor.execute(() -> mCallback.onJoinCalls(requestId, uuids));
+            } finally {
+                Binder.restoreCallingIdentity(identityToken);
+            }
+        }
+    };
+
+    private Context mContext;
+    private ServiceListener mServiceListener;
+    private volatile IBluetoothLeCallControl mService;
+    private BluetoothAdapter mAdapter;
+    private int mCcid = 0;
+    private String mToken;
+    private Callback mCallback = null;
+    private Object mServerIfLock = new Object();
+
+    private final IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
+        new IBluetoothStateChangeCallback.Stub() {
+        public void onBluetoothStateChange(boolean up) {
+            if (DBG)
+                Log.d(TAG, "onBluetoothStateChange: up=" + up);
+            if (!up) {
+                doUnbind();
+            } else {
+                doBind();
+            }
+        }
+    };
+
+    /**
+     * Create a BluetoothLeCallControl proxy object for interacting with the local Bluetooth
+     * telephone bearer service.
+     */
+    /* package */ BluetoothLeCallControl(Context context, ServiceListener listener) {
+        mContext = context;
+        mAdapter = BluetoothAdapter.getDefaultAdapter();
+        mServiceListener = listener;
+
+        IBluetoothManager mgr = mAdapter.getBluetoothManager();
+        if (mgr != null) {
+            try {
+                mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
+            } catch (RemoteException e) {
+                Log.e(TAG, "", e);
+            }
+        }
+
+        doBind();
+    }
+
+    private boolean doBind() {
+        synchronized (mConnection) {
+            if (mService == null) {
+                if (VDBG)
+                    Log.d(TAG, "Binding service...");
+                try {
+                    return mAdapter.getBluetoothManager().
+                            bindBluetoothProfileService(BluetoothProfile.LE_CALL_CONTROL,
+                            mConnection);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Unable to bind TelephoneBearerService", e);
+                }
+            }
+        }
+        return false;
+    }
+
+    private void doUnbind() {
+        synchronized (mConnection) {
+            if (mService != null) {
+                if (VDBG)
+                    Log.d(TAG, "Unbinding service...");
+                try {
+                    mAdapter.getBluetoothManager().
+                        unbindBluetoothProfileService(BluetoothProfile.LE_CALL_CONTROL,
+                        mConnection);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Unable to unbind TelephoneBearerService", e);
+                } finally {
+                    mService = null;
+                }
+            }
+        }
+    }
+
+    /* package */ void close() {
+        if (VDBG)
+            log("close()");
+        unregisterBearer();
+
+        IBluetoothManager mgr = mAdapter.getBluetoothManager();
+        if (mgr != null) {
+            try {
+                mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
+            } catch (RemoteException re) {
+                Log.e(TAG, "", re);
+            }
+        }
+        mServiceListener = null;
+        doUnbind();
+    }
+
+    private IBluetoothLeCallControl getService() {
+        return mService;
+    }
+
+    /**
+     * Not supported
+     *
+     * @throws UnsupportedOperationException
+     */
+    @Override
+    public int getConnectionState(@Nullable BluetoothDevice device) {
+        throw new UnsupportedOperationException("not supported");
+    }
+
+    /**
+     * Not supported
+     *
+     * @throws UnsupportedOperationException
+     */
+    @Override
+    public @NonNull List<BluetoothDevice> getConnectedDevices() {
+        throw new UnsupportedOperationException("not supported");
+    }
+
+    /**
+     * Not supported
+     *
+     * @throws UnsupportedOperationException
+     */
+    @Override
+    public @NonNull List<BluetoothDevice> getDevicesMatchingConnectionStates(
+        @NonNull int[] states) {
+        throw new UnsupportedOperationException("not supported");
+    }
+
+    /**
+     * Register Telephone Bearer exposing the interface that allows remote devices
+     * to track and control the call states.
+     *
+     * <p>
+     * This is an asynchronous call. The callback is used to notify success or
+     * failure if the function returns true.
+     *
+     * <p>
+     * Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+     *
+     * <!-- The UCI is a String identifier of the telephone bearer as defined at
+     * https://www.bluetooth.com/specifications/assigned-numbers/uniform-caller-identifiers
+     * (login required). -->
+     *
+     * <!-- The examples of common URI schemes can be found in
+     * https://iana.org/assignments/uri-schemes/uri-schemes.xhtml -->
+     *
+     * <!-- The Technology is an integer value. The possible values are defined at
+     * https://www.bluetooth.com/specifications/assigned-numbers (login required).
+     * -->
+     *
+     * @param uci          Bearer Unique Client Identifier
+     * @param uriSchemes   URI Schemes supported list
+     * @param capabilities bearer capabilities
+     * @param provider     Network provider name
+     * @param technology   Network technology
+     * @param executor     {@link Executor} object on which callback will be
+     *                     executed. The Executor object is required.
+     * @param callback     {@link Callback} object to which callback messages will
+     *                     be sent. The Callback object is required.
+     * @return true on success, false otherwise
+     * @hide
+     */
+    @SuppressLint("ExecutorRegistration")
+    @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
+    public boolean registerBearer(@Nullable String uci,
+                    @NonNull List<String> uriSchemes, int capabilities,
+                    @NonNull String provider, int technology,
+                    @NonNull Executor executor, @NonNull Callback callback) {
+        if (DBG) {
+            Log.d(TAG, "registerBearer");
+        }
+        if (callback == null) {
+            throw new IllegalArgumentException("null parameter: " + callback);
+        }
+        if (mCcid != 0) {
+            return false;
+        }
+
+        mToken = uci;
+
+        final IBluetoothLeCallControl service = getService();
+        if (service != null) {
+            synchronized (mServerIfLock) {
+                if (mCallback != null) {
+                    Log.e(TAG, "Bearer can be opened only once");
+                    return false;
+                }
+
+                mCallback = callback;
+                try {
+                    CallbackWrapper callbackWrapper = new CallbackWrapper(executor, callback);
+                    service.registerBearer(mToken, callbackWrapper, uci, uriSchemes, capabilities,
+                                            provider, technology);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "", e);
+                    mCallback = null;
+                    return false;
+                }
+
+                try {
+                    mServerIfLock.wait(REG_TIMEOUT);
+                } catch (InterruptedException e) {
+                    Log.e(TAG, "" + e);
+                    mCallback = null;
+                }
+
+                if (mCcid == 0) {
+                    mCallback = null;
+                    return false;
+                }
+
+                return true;
+            }
+        }
+        if (service == null) {
+            Log.w(TAG, "Proxy not attached to service");
+        }
+
+        return false;
+    }
+
+    /**
+     * Unregister Telephone Bearer Service and destroy all the associated data.
+     *
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
+    public void unregisterBearer() {
+        if (DBG) {
+            Log.d(TAG, "unregisterBearer");
+        }
+        if (mCcid == 0) {
+            return;
+        }
+
+        int ccid = mCcid;
+        mCcid = 0;
+        mCallback = null;
+
+        final IBluetoothLeCallControl service = getService();
+        if (service != null) {
+            try {
+                service.unregisterBearer(mToken);
+            } catch (RemoteException e) {
+                Log.e(TAG, "", e);
+            }
+        }
+        if (service == null) {
+            Log.w(TAG, "Proxy not attached to service");
+        }
+    }
+
+    /**
+     * Get the Content Control ID (CCID) value.
+     *
+     * @return ccid Content Control ID value
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
+    public int getContentControlId() {
+        return mCcid;
+    }
+
+    /**
+     * Notify about the newly added call.
+     *
+     * <p>
+     * This shall be called as early as possible after the call has been added.
+     *
+     * <p>
+     * Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+     *
+     * @param call Newly added call
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
+    public void onCallAdded(@NonNull BluetoothLeCall call) {
+        if (DBG) {
+            Log.d(TAG, "onCallAdded: call=" + call);
+        }
+        if (mCcid == 0) {
+            return;
+        }
+
+        final IBluetoothLeCallControl service = getService();
+        if (service != null) {
+            try {
+                service.callAdded(mCcid, call);
+            } catch (RemoteException e) {
+                Log.e(TAG, "", e);
+            }
+        }
+        if (service == null) {
+            Log.w(TAG, "Proxy not attached to service");
+        }
+    }
+
+    /**
+     * Notify about the removed call.
+     *
+     * <p>
+     * This shall be called as early as possible after the call has been removed.
+     *
+     * <p>
+     * Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+     *
+     * @param callId The Id of a call that has been removed
+     * @param reason Call termination reason
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
+    public void onCallRemoved(@NonNull UUID callId, @TerminationReason int reason) {
+        if (DBG) {
+            Log.d(TAG, "callRemoved: callId=" + callId);
+        }
+        if (mCcid == 0) {
+            return;
+        }
+
+        final IBluetoothLeCallControl service = getService();
+        if (service != null) {
+            try {
+                service.callRemoved(mCcid, new ParcelUuid(callId), reason);
+            } catch (RemoteException e) {
+                Log.e(TAG, "", e);
+            }
+        }
+        if (service == null) {
+            Log.w(TAG, "Proxy not attached to service");
+        }
+    }
+
+    /**
+     * Notify the call state change
+     *
+     * <p>
+     * This shall be called as early as possible after the state of the call has
+     * changed.
+     *
+     * <p>
+     * Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+     *
+     * @param callId The call Id that state has been changed
+     * @param state  Call state
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
+    public void onCallStateChanged(@NonNull UUID callId, @BluetoothLeCall.State int state) {
+        if (DBG) {
+            Log.d(TAG, "callStateChanged: callId=" + callId + " state=" + state);
+        }
+        if (mCcid == 0) {
+            return;
+        }
+
+        final IBluetoothLeCallControl service = getService();
+        if (service != null) {
+            try {
+                service.callStateChanged(mCcid, new ParcelUuid(callId), state);
+            } catch (RemoteException e) {
+                Log.e(TAG, "", e);
+            }
+        }
+        if (service == null) {
+            Log.w(TAG, "Proxy not attached to service");
+        }
+    }
+
+    /**
+     * Provide the current calls list
+     *
+     * <p>
+     * This function must be invoked after registration if application has any
+     * calls.
+     *
+     * @param calls current calls list
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
+     public void currentCallsList(@NonNull List<BluetoothLeCall> calls) {
+        final IBluetoothLeCallControl service = getService();
+        if (service != null) {
+            try {
+                service.currentCallsList(mCcid, calls);
+            } catch (RemoteException e) {
+                Log.e(TAG, "", e);
+            }
+        }
+    }
+
+    /**
+     * Provide the network current status
+     *
+     * <p>
+     * This function must be invoked on change of network state.
+     *
+     * <p>
+     * Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+     *
+     * <!-- The Technology is an integer value. The possible values are defined at
+     * https://www.bluetooth.com/specifications/assigned-numbers (login required).
+     * -->
+     *
+     * @param provider   Network provider name
+     * @param technology Network technology
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
+    public void networkStateChanged(@NonNull String provider, int technology) {
+        if (DBG) {
+            Log.d(TAG, "networkStateChanged: provider=" + provider + ", technology=" + technology);
+        }
+        if (mCcid == 0) {
+            return;
+        }
+
+        final IBluetoothLeCallControl service = getService();
+        if (service != null) {
+            try {
+                service.networkStateChanged(mCcid, provider, technology);
+            } catch (RemoteException e) {
+                Log.e(TAG, "", e);
+            }
+        }
+        if (service == null) {
+            Log.w(TAG, "Proxy not attached to service");
+        }
+    }
+
+    /**
+     * Send a response to a call control request to a remote device.
+     *
+     * <p>
+     * This function must be invoked in when a request is received by one of these
+     * callback methods:
+     *
+     * <ul>
+     * <li>{@link Callback#onAcceptCall}
+     * <li>{@link Callback#onTerminateCall}
+     * <li>{@link Callback#onHoldCall}
+     * <li>{@link Callback#onUnholdCall}
+     * <li>{@link Callback#onPlaceCall}
+     * <li>{@link Callback#onJoinCalls}
+     * </ul>
+     *
+     * @param requestId The ID of the request that was received with the callback
+     * @param result    The result of the request to be sent to the remote devices
+     */
+    @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
+    public void requestResult(int requestId, @Result int result) {
+        if (DBG) {
+            Log.d(TAG, "requestResult: requestId=" + requestId + " result=" + result);
+        }
+        if (mCcid == 0) {
+            return;
+        }
+
+        final IBluetoothLeCallControl service = getService();
+        if (service != null) {
+            try {
+                service.requestResult(mCcid, requestId, result);
+            } catch (RemoteException e) {
+                Log.e(TAG, "", e);
+            }
+        }
+    }
+
+    @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
+    private static boolean isValidDevice(@Nullable BluetoothDevice device) {
+        return device != null && BluetoothAdapter.checkBluetoothAddress(device.getAddress());
+    }
+
+    private static void log(String msg) {
+        Log.d(TAG, msg);
+    }
+
+    private final IBluetoothProfileServiceConnection mConnection =
+                                    new IBluetoothProfileServiceConnection.Stub() {
+        @Override
+        public void onServiceConnected(ComponentName className, IBinder service) {
+            if (DBG) {
+                Log.d(TAG, "Proxy object connected");
+            }
+            mService = IBluetoothLeCallControl.Stub.asInterface(Binder.allowBlocking(service));
+            mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_TBS_SERVICE_CONNECTED));
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName className) {
+            if (DBG) {
+                Log.d(TAG, "Proxy object disconnected");
+            }
+            doUnbind();
+            mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_TBS_SERVICE_DISCONNECTED));
+        }
+    };
+
+    private final Handler mHandler = new Handler(Looper.getMainLooper()) {
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+            case MESSAGE_TBS_SERVICE_CONNECTED: {
+                if (mServiceListener != null) {
+                    mServiceListener.onServiceConnected(BluetoothProfile.LE_CALL_CONTROL,
+                        BluetoothLeCallControl.this);
+                }
+                break;
+            }
+            case MESSAGE_TBS_SERVICE_DISCONNECTED: {
+                if (mServiceListener != null) {
+                    mServiceListener.onServiceDisconnected(BluetoothProfile.LE_CALL_CONTROL);
+                }
+                break;
+            }
+            }
+        }
+    };
+}
diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java
index e047e5d..d0f74e9 100644
--- a/core/java/android/bluetooth/BluetoothProfile.java
+++ b/core/java/android/bluetooth/BluetoothProfile.java
@@ -240,12 +240,19 @@
     int LE_AUDIO_BROADCAST = 26;
 
     /**
+     * @hide
+     * Telephone Bearer Service from Call Control Profile
+     *
+     */
+    int LE_CALL_CONTROL = 27;
+
+    /**
      * 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 = 26;
+    int MAX_PROFILE_ID = 27;
 
     /**
      * Default priority for devices that we try to auto-connect to and
diff --git a/core/java/android/bluetooth/BluetoothUuid.java b/core/java/android/bluetooth/BluetoothUuid.java
index bb537dd..2a8ff51 100644
--- a/core/java/android/bluetooth/BluetoothUuid.java
+++ b/core/java/android/bluetooth/BluetoothUuid.java
@@ -189,7 +189,7 @@
     @NonNull
     @SystemApi
     public static final ParcelUuid CAP =
-            ParcelUuid.fromString("00008FE0-0000-1000-8000-00805F9B34FB");
+            ParcelUuid.fromString("00001853-0000-1000-8000-00805F9B34FB");
     /** @hide */
     @NonNull
     @SystemApi
diff --git a/core/java/android/companion/AssociationInfo.java b/core/java/android/companion/AssociationInfo.java
index 3f02aa2..78d5137 100644
--- a/core/java/android/companion/AssociationInfo.java
+++ b/core/java/android/companion/AssociationInfo.java
@@ -197,6 +197,20 @@
         return macAddress.equals(mDeviceMacAddress);
     }
 
+    /** @hide */
+    public @NonNull String toShortString() {
+        final StringBuilder sb = new StringBuilder();
+        sb.append("id=").append(mId);
+        if (mDeviceMacAddress != null) {
+            sb.append(", addr=").append(getDeviceMacAddressAsString());
+        }
+        if (mSelfManaged) {
+            sb.append(", self-managed");
+        }
+        sb.append(", pkg=u").append(mUserId).append('/').append(mPackageName);
+        return sb.toString();
+    }
+
     @Override
     public String toString() {
         return "Association{"
diff --git a/core/java/android/content/ContentProviderClient.java b/core/java/android/content/ContentProviderClient.java
index 518e753..cc3c012 100644
--- a/core/java/android/content/ContentProviderClient.java
+++ b/core/java/android/content/ContentProviderClient.java
@@ -109,7 +109,7 @@
         mAuthority = authority;
         mStable = stable;
 
-        mCloseGuard.open("close");
+        mCloseGuard.open("ContentProviderClient.close");
     }
 
     /**
@@ -695,7 +695,7 @@
 
         CursorWrapperInner(Cursor cursor) {
             super(cursor);
-            mCloseGuard.open("close");
+            mCloseGuard.open("CursorWrapperInner.close");
         }
 
         @Override
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 184acb1..01d231c 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -3858,7 +3858,7 @@
         CursorWrapperInner(Cursor cursor, IContentProvider contentProvider) {
             super(cursor);
             mContentProvider = contentProvider;
-            mCloseGuard.open("close");
+            mCloseGuard.open("CursorWrapperInner.close");
         }
 
         @Override
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 6d13712..bccfacf 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -534,7 +534,8 @@
 
     /** @hide */
     @IntDef(flag = true, prefix = { "RECEIVER_VISIBLE" }, value = {
-            RECEIVER_VISIBLE_TO_INSTANT_APPS, RECEIVER_EXPORTED, RECEIVER_NOT_EXPORTED
+            RECEIVER_VISIBLE_TO_INSTANT_APPS, RECEIVER_EXPORTED, RECEIVER_NOT_EXPORTED,
+            RECEIVER_EXPORTED_UNAUDITED
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface RegisterReceiverFlags {}
@@ -551,6 +552,14 @@
     public static final int RECEIVER_EXPORTED = 0x2;
 
     /**
+     * @deprecated Use {@link #RECEIVER_NOT_EXPORTED} or {@link #RECEIVER_EXPORTED} instead.
+     * @hide
+     */
+    @Deprecated
+    @TestApi
+    public static final int RECEIVER_EXPORTED_UNAUDITED = RECEIVER_EXPORTED;
+
+    /**
      * 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"
      */
@@ -3606,9 +3615,8 @@
      *          {@link #BIND_ADJUST_WITH_ACTIVITY}.
      * @return {@code true} if the system is in the process of bringing up a
      *         service that your client has permission to bind to; {@code false}
-     *         if the system couldn't find the service. If this value is {@code true}, you
-     *         should later call {@link #unbindService} to release the
-     *         connection.
+     *         if the system couldn't find the service. You should call {@link #unbindService}
+     *         to release the connection even if this method returned {@code false}.
      *
      * @throws SecurityException if the client does not have the required permission to bind.
      */
@@ -5914,6 +5922,7 @@
      * @see android.nearby.NearbyManager
      * @hide
      */
+    @SystemApi
     public static final String NEARBY_SERVICE = "nearby";
 
     /**
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 1e6029f..af84392 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -3794,6 +3794,47 @@
             "android.intent.action.ACTION_IDLE_MAINTENANCE_END";
 
     /**
+     * Broadcast Action: A broadcast sent by the system to indicate that
+     * {@link android.safetycenter.SafetyCenterManager} is requesting data from safety sources
+     * regarding their safety state.
+     *
+     * This broadcast is sent when a user triggers a data refresh from the Safety Center UI or when
+     * Safety Center detects that its stored safety information is stale and needs to be updated.
+     *
+     * This broadcast is sent explicitly to safety sources by targeting intents to a specified set
+     * of components provided by the safety sources in the safety source configuration.
+     * The receiving components should be manifest-declared receivers so that safety sources can be
+     * requested to send data even if they are not running.
+     *
+     * On receiving this broadcast, safety sources should determine their safety state
+     * according to the parameters specified in the intent extras (see below) and send Safety Center
+     * data about their safety state using
+     * {@link android.safetycenter.SafetyCenterManager#sendSafetyCenterUpdate(android.safetycenter.SafetySourceData)}.
+     *
+     * <p class="note">This is a protected intent that can only be sent by the system.
+     *
+     * <p>Includes the following extras:
+     * <ul>
+     * <li>{@link #EXTRA_REFRESH_SAFETY_SOURCES_REQUEST_TYPE}: An int representing the type of data
+     * being requested. Possible values are all values in {@link RefreshRequestType}.
+     * <li>{@link #EXTRA_REFRESH_SAFETY_SOURCE_IDS}: A {@code String[]} of ids
+     * representing the safety sources being requested for data. This extra exists for
+     * disambiguation in the case that a single component is responsible for receiving refresh
+     * requests for multiple safety sources.
+     * </ul>
+     *
+     * @hide
+     */
+    // TODO(b/210805082): Define the term "safety sources" more concretely here once safety sources
+    //  are configured in xml config.
+    // TODO(b/210979035): Determine recommendation for sources if they are requested for fresh data
+    //  but cannot provide it.
+    @SystemApi
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_REFRESH_SAFETY_SOURCES =
+            "android.intent.action.REFRESH_SAFETY_SOURCES";
+
+    /**
      * Broadcast Action: a remote intent is to be broadcasted.
      *
      * A remote intent is used for remote RPC between devices. The remote intent
@@ -5598,7 +5639,9 @@
      *
      * <p>Targets provided in this way will be presented inline with all other targets provided
      * by services from other apps. They will be prioritized before other service targets, but
-     * after those targets provided by sources that the user has manually pinned to the front.</p>
+     * after those targets provided by sources that the user has manually pinned to the front.
+     * You can provide up to two targets on this extra (the limit of two targets
+     * starts in Android 10).</p>
      *
      * @see #ACTION_CHOOSER
      */
@@ -5709,9 +5752,11 @@
     /**
      * A Parcelable[] of {@link Intent} or
      * {@link android.content.pm.LabeledIntent} objects as set with
-     * {@link #putExtra(String, Parcelable[])} of additional activities to place
-     * a the front of the list of choices, when shown to the user with a
-     * {@link #ACTION_CHOOSER}.
+     * {@link #putExtra(String, Parcelable[])} to place
+     * at the front of the list of choices, when shown to the user with an
+     * {@link #ACTION_CHOOSER}. You can choose up to two additional activities
+     * to show before the app suggestions (the limit of two additional activities starts in
+     * Android 10).
      */
     public static final String EXTRA_INITIAL_INTENTS = "android.intent.extra.INITIAL_INTENTS";
 
@@ -6382,6 +6427,77 @@
     public static final String EXTRA_VISIBILITY_ALLOW_LIST =
             "android.intent.extra.VISIBILITY_ALLOW_LIST";
 
+
+    /**
+     * Used as a {@code String[]} extra field in
+     * {@link android.content.Intent#ACTION_REFRESH_SAFETY_SOURCES} intents to specify the safety
+     * source ids of the safety sources being requested for data by Safety Center.
+     *
+     * When this extra field is not specified in the intent, it is assumed that Safety Center is
+     * requesting data from all safety sources supported by the component receiving the broadcast.
+     * @hide
+     */
+    @SystemApi
+    public static final String EXTRA_REFRESH_SAFETY_SOURCE_IDS =
+            "android.intent.extra.REFRESH_SAFETY_SOURCE_IDS";
+
+    /**
+     * Used as an {@code int} extra field in
+     * {@link android.content.Intent#ACTION_REFRESH_SAFETY_SOURCES} intents to specify the type of
+     * data request from Safety Center.
+     *
+     * Possible values are all values in {@link RefreshRequestType}.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String EXTRA_REFRESH_SAFETY_SOURCES_REQUEST_TYPE =
+            "android.intent.extra.REFRESH_SAFETY_SOURCES_REQUEST_TYPE";
+
+    /**
+     * All possible types of data refresh requests in broadcasts with intent action
+     * {@link android.content.Intent#ACTION_REFRESH_SAFETY_SOURCES}.
+     *
+     * @hide
+     */
+    @IntDef(prefix = { "EXTRA_REFRESH_REQUEST_TYPE_" }, value = {
+            EXTRA_REFRESH_REQUEST_TYPE_FETCH_FRESH_DATA,
+            EXTRA_REFRESH_REQUEST_TYPE_GET_DATA,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface RefreshRequestType {}
+
+    /**
+     * Used as an int value for
+     * {@link android.content.Intent#EXTRA_REFRESH_SAFETY_SOURCES_REQUEST_TYPE}
+     * to indicate that the safety source should fetch fresh data relating to their safety state
+     * upon receiving a broadcast with intent action
+     * {@link android.content.Intent#ACTION_REFRESH_SAFETY_SOURCES} and provide it to Safety Center.
+     *
+     * The term "fresh" here means that the sources should ensure that the safety data is accurate
+     * as possible at the time of providing it to Safety Center, even if it involves performing an
+     * expensive and/or slow process.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int EXTRA_REFRESH_REQUEST_TYPE_FETCH_FRESH_DATA = 0;
+
+    /**
+     * Used as an int value for
+     * {@link android.content.Intent#EXTRA_REFRESH_SAFETY_SOURCES_REQUEST_TYPE}
+     * to indicate that upon receiving a broadcasts with intent action
+     * {@link android.content.Intent#ACTION_REFRESH_SAFETY_SOURCES}, the safety source should
+     * provide data relating to their safety state to Safety Center.
+     *
+     * If the source already has its safety data cached, it may provide it without triggering a
+     * process to fetch state which may be expensive and/or slow.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int EXTRA_REFRESH_REQUEST_TYPE_GET_DATA = 1;
+
     // ---------------------------------------------------------------------
     // ---------------------------------------------------------------------
     // Intent flags (see mFlags variable).
diff --git a/core/java/android/content/pm/ILauncherApps.aidl b/core/java/android/content/pm/ILauncherApps.aidl
index 37fd3ff..cb8988e 100644
--- a/core/java/android/content/pm/ILauncherApps.aidl
+++ b/core/java/android/content/pm/ILauncherApps.aidl
@@ -38,6 +38,8 @@
 import android.os.UserHandle;
 import android.os.ParcelFileDescriptor;
 
+import com.android.internal.infra.AndroidFuture;
+
 import java.util.List;
 
 /**
@@ -73,6 +75,8 @@
 
     ParceledListSlice getShortcuts(String callingPackage, in ShortcutQueryWrapper query,
             in UserHandle user);
+    void getShortcutsAsync(String callingPackage, in ShortcutQueryWrapper query,
+            in UserHandle user, in AndroidFuture<List<ShortcutInfo>> cb);
     void pinShortcuts(String callingPackage, String packageName, in List<String> shortcutIds,
             in UserHandle user);
     boolean startShortcut(String callingPackage, String packageName, String featureId, String id,
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 617d3ab..a0d348f 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -69,6 +69,7 @@
 import android.util.Pair;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.infra.AndroidFuture;
 import com.android.internal.util.function.pooled.PooledLambda;
 
 import java.io.FileNotFoundException;
@@ -84,6 +85,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Executor;
 
 /**
@@ -440,6 +442,17 @@
         public static final int FLAG_GET_KEY_FIELDS_ONLY = 1 << 2;
 
         /**
+         * Includes shortcuts from persistence layer in the search result.
+         *
+         * <p>The caller should make the query on a worker thread since accessing persistence layer
+         * is considered asynchronous.
+         *
+         * @hide
+         */
+        @SystemApi
+        public static final int FLAG_GET_PERSISTED_DATA = 1 << 12;
+
+        /**
          * Populate the persons field in the result. See {@link ShortcutInfo#getPersons()}.
          *
          * <p>The caller must have the system {@code ACCESS_SHORTCUTS} permission.
@@ -459,6 +472,7 @@
                 FLAG_MATCH_PINNED_BY_ANY_LAUNCHER,
                 FLAG_GET_KEY_FIELDS_ONLY,
                 FLAG_GET_PERSONS_DATA,
+                FLAG_GET_PERSISTED_DATA
         })
         @Retention(RetentionPolicy.SOURCE)
         public @interface QueryFlags {}
@@ -1137,6 +1151,9 @@
             @NonNull UserHandle user) {
         logErrorForInvalidProfileAccess(user);
         try {
+            if ((query.mQueryFlags & ShortcutQuery.FLAG_GET_PERSISTED_DATA) != 0) {
+                return getShortcutsBlocked(query, user);
+            }
             // Note this is the only case we need to update the disabled message for shortcuts
             // that weren't restored.
             // The restore problem messages are only shown by the user, and publishers will never
@@ -1144,13 +1161,29 @@
             // changed callback, but that only returns shortcuts with the "key" information, so
             // that won't return disabled message.
             return maybeUpdateDisabledMessage(mService.getShortcuts(mContext.getPackageName(),
-                    new ShortcutQueryWrapper(query), user)
-                    .getList());
+                                new ShortcutQueryWrapper(query), user)
+                        .getList());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
     }
 
+    private List<ShortcutInfo> getShortcutsBlocked(@NonNull ShortcutQuery query,
+            @NonNull UserHandle user) {
+        logErrorForInvalidProfileAccess(user);
+        final AndroidFuture<List<ShortcutInfo>> future = new AndroidFuture<>();
+        future.thenApply(this::maybeUpdateDisabledMessage);
+        try {
+            mService.getShortcutsAsync(mContext.getPackageName(),
+                            new ShortcutQueryWrapper(query), user, future);
+            return future.get();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        } catch (InterruptedException | ExecutionException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
     /**
      * @hide // No longer used.  Use getShortcuts() instead.  Kept for unit tests.
      */
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 251d5e8..495100b 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -2374,7 +2374,7 @@
                 STAGED_SESSION_UNKNOWN,
                 STAGED_SESSION_CONFLICT})
         @Retention(RetentionPolicy.SOURCE)
-        public @interface StagedSessionErrorCode{}
+        public @interface SessionErrorCode {}
         /**
          * Constant indicating that no error occurred during the preparation or the activation of
          * this staged session.
@@ -2486,13 +2486,13 @@
         public int[] childSessionIds = NO_SESSIONS;
 
         /** {@hide} */
-        public boolean isStagedSessionApplied;
+        public boolean isSessionApplied;
         /** {@hide} */
-        public boolean isStagedSessionReady;
+        public boolean isSessionReady;
         /** {@hide} */
-        public boolean isStagedSessionFailed;
-        private int mStagedSessionErrorCode;
-        private String mStagedSessionErrorMessage;
+        public boolean isSessionFailed;
+        private int mSessionErrorCode;
+        private String mSessionErrorMessage;
 
         /** {@hide} */
         public boolean isCommitted;
@@ -2553,11 +2553,11 @@
             if (childSessionIds == null) {
                 childSessionIds = NO_SESSIONS;
             }
-            isStagedSessionApplied = source.readBoolean();
-            isStagedSessionReady = source.readBoolean();
-            isStagedSessionFailed = source.readBoolean();
-            mStagedSessionErrorCode = source.readInt();
-            mStagedSessionErrorMessage = source.readString();
+            isSessionApplied = source.readBoolean();
+            isSessionReady = source.readBoolean();
+            isSessionFailed = source.readBoolean();
+            mSessionErrorCode = source.readInt();
+            mSessionErrorMessage = source.readString();
             isCommitted = source.readBoolean();
             rollbackDataPolicy = source.readInt();
             createdMillis = source.readLong();
@@ -2951,7 +2951,7 @@
          * since that is the one that should have been {@link Session#commit committed}.
          */
         public boolean isStagedSessionActive() {
-            return isStaged && isCommitted && !isStagedSessionApplied && !isStagedSessionFailed
+            return isStaged && isCommitted && !isSessionApplied && !isSessionFailed
                     && !hasParentSessionId();
         }
 
@@ -2992,7 +2992,7 @@
          */
         public boolean isStagedSessionApplied() {
             checkSessionIsStaged();
-            return isStagedSessionApplied;
+            return isSessionApplied;
         }
 
         /**
@@ -3001,7 +3001,7 @@
          */
         public boolean isStagedSessionReady() {
             checkSessionIsStaged();
-            return isStagedSessionReady;
+            return isSessionReady;
         }
 
         /**
@@ -3010,16 +3010,16 @@
          */
         public boolean isStagedSessionFailed() {
             checkSessionIsStaged();
-            return isStagedSessionFailed;
+            return isSessionFailed;
         }
 
         /**
          * If something went wrong with a staged session, clients can check this error code to
          * understand which kind of failure happened. Only meaningful if {@code isStaged} is true.
          */
-        public @StagedSessionErrorCode int getStagedSessionErrorCode() {
+        public @SessionErrorCode int getStagedSessionErrorCode() {
             checkSessionIsStaged();
-            return mStagedSessionErrorCode;
+            return mSessionErrorCode;
         }
 
         /**
@@ -3028,14 +3028,13 @@
          */
         public @NonNull String getStagedSessionErrorMessage() {
             checkSessionIsStaged();
-            return mStagedSessionErrorMessage;
+            return mSessionErrorMessage;
         }
 
         /** {@hide} */
-        public void setStagedSessionErrorCode(@StagedSessionErrorCode int errorCode,
-                                              String errorMessage) {
-            mStagedSessionErrorCode = errorCode;
-            mStagedSessionErrorMessage = errorMessage;
+        public void setSessionErrorCode(@SessionErrorCode int errorCode, String errorMessage) {
+            mSessionErrorCode = errorCode;
+            mSessionErrorMessage = errorMessage;
         }
 
         /**
@@ -3124,11 +3123,11 @@
             dest.writeBoolean(forceQueryable);
             dest.writeInt(parentSessionId);
             dest.writeIntArray(childSessionIds);
-            dest.writeBoolean(isStagedSessionApplied);
-            dest.writeBoolean(isStagedSessionReady);
-            dest.writeBoolean(isStagedSessionFailed);
-            dest.writeInt(mStagedSessionErrorCode);
-            dest.writeString(mStagedSessionErrorMessage);
+            dest.writeBoolean(isSessionApplied);
+            dest.writeBoolean(isSessionReady);
+            dest.writeBoolean(isSessionFailed);
+            dest.writeInt(mSessionErrorCode);
+            dest.writeString(mSessionErrorMessage);
             dest.writeBoolean(isCommitted);
             dest.writeInt(rollbackDataPolicy);
             dest.writeLong(createdMillis);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 973fe01..338dfd6 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -145,6 +145,20 @@
             "android.media.PROPERTY_MEDIA_CAPABILITIES";
 
     /**
+     * Application level property that an app can specify to opt-out from having private data
+     * directories both on the internal and external storages.
+     *
+     * <p>Changing the value of this property during app update is not supported, and such updates
+     * will be rejected.
+     *
+     * <p>This should only be set by platform apps that know what they are doing.
+     *
+     * @hide
+     */
+    public static final String PROPERTY_NO_APP_DATA_STORAGE =
+            "android.internal.PROPERTY_NO_APP_DATA_STORAGE";
+
+    /**
      * A property value set within the manifest.
      * <p>
      * The value of a property will only have a single type, as defined by
@@ -3735,14 +3749,6 @@
     public static final String FEATURE_MANAGED_PROFILES = "android.software.managed_users";
 
     /**
-     * @hide
-     * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
-     * The device supports Nearby mainline feature.
-     */
-    @SdkConstant(SdkConstantType.FEATURE)
-    public static final String FEATURE_NEARBY = "android.software.nearby";
-
-    /**
      * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
      * The device supports verified boot.
      */
diff --git a/core/java/android/content/pm/ShortcutServiceInternal.java b/core/java/android/content/pm/ShortcutServiceInternal.java
index 3ed5c64..087a795 100644
--- a/core/java/android/content/pm/ShortcutServiceInternal.java
+++ b/core/java/android/content/pm/ShortcutServiceInternal.java
@@ -29,6 +29,8 @@
 import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
 
+import com.android.internal.infra.AndroidFuture;
+
 import java.util.List;
 
 /**
@@ -50,6 +52,19 @@
             @Nullable List<LocusId> locusIds, @Nullable ComponentName componentName,
             @ShortcutQuery.QueryFlags int flags, int userId, int callingPid, int callingUid);
 
+    /**
+     * Retrieves shortcuts asynchronously. Query will go through persistence layer (thus making the
+     * call async) if querying by shortcutIds in a specific package; otherwise it's effectively the
+     * same as calling {@link #getShortcuts}.
+     */
+    public abstract void
+            getShortcutsAsync(int launcherUserId,
+            @NonNull String callingPackage, long changedSince,
+            @Nullable String packageName, @Nullable List<String> shortcutIds,
+            @Nullable List<LocusId> locusIds, @Nullable ComponentName componentName,
+            @ShortcutQuery.QueryFlags int flags, int userId, int callingPid, int callingUid,
+            AndroidFuture<List<ShortcutInfo>> cb);
+
     public abstract boolean
             isPinnedByCaller(int launcherUserId, @NonNull String callingPackage,
             @NonNull String packageName, @NonNull String id, int userId);
@@ -63,6 +78,14 @@
             @NonNull String packageName, @NonNull String shortcutId, int userId,
             int callingPid, int callingUid);
 
+    /**
+     * Retrieves the intents from a specified shortcut asynchronously.
+     */
+    public abstract void createShortcutIntentsAsync(
+            int launcherUserId, @NonNull String callingPackage,
+            @NonNull String packageName, @NonNull String shortcutId, int userId,
+            int callingPid, int callingUid, @NonNull AndroidFuture<Intent[]> cb);
+
     public abstract void addListener(@NonNull ShortcutChangeListener listener);
 
     public abstract void addShortcutChangeCallback(
@@ -82,6 +105,13 @@
             @NonNull String callingPackage,
             @NonNull String packageName, @NonNull String shortcutId, int userId);
 
+    /**
+     * Retrieves a file descriptor from the icon in a specified shortcut asynchronously.
+     */
+    public abstract void getShortcutIconFdAsync(int launcherUserId, @NonNull String callingPackage,
+            @NonNull String packageName, @NonNull String shortcutId, int userId,
+            @NonNull AndroidFuture<ParcelFileDescriptor> cb);
+
     public abstract boolean hasShortcutHostPermission(int launcherUserId,
             @NonNull String callingPackage, int callingPid, int callingUid);
 
@@ -117,6 +147,14 @@
     public abstract String getShortcutIconUri(int launcherUserId, @NonNull String launcherPackage,
             @NonNull String packageName, @NonNull String shortcutId, int userId);
 
+    /**
+     * Retrieves the icon Uri of the shortcut asynchronously, and grants Uri read permission to the
+     * caller.
+     */
+    public abstract void getShortcutIconUriAsync(int launcherUserId,
+            @NonNull String launcherPackage, @NonNull String packageName,
+            @NonNull String shortcutId, int userId, @NonNull AndroidFuture<String> cb);
+
     public abstract boolean isSharingShortcut(int callingUserId, @NonNull String callingPackage,
             @NonNull String packageName, @NonNull String shortcutId, int userId,
             @NonNull IntentFilter filter);
diff --git a/core/java/android/content/pm/TEST_MAPPING b/core/java/android/content/pm/TEST_MAPPING
index 26f0826..77b8be3 100644
--- a/core/java/android/content/pm/TEST_MAPPING
+++ b/core/java/android/content/pm/TEST_MAPPING
@@ -59,6 +59,72 @@
           "include-filter": "android.content.pm.cts"
         }
       ]
+    },
+    {
+      "name": "CtsUsesNativeLibraryTest",
+      "options": [
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        },
+        {
+          "exclude-annotation": "org.junit.Ignore"
+        }
+      ]
+    },
+    {
+      "name": "CtsAppSearchHostTestCases",
+      "options": [
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        },
+        {
+          "exclude-annotation": "org.junit.Ignore"
+        }
+      ]
+    },
+    {
+      "name": "CtsSilentUpdateHostTestCases",
+      "options": [
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        },
+        {
+          "exclude-annotation": "org.junit.Ignore"
+        }
+      ]
+    },
+    {
+      "name": "CtsSuspendAppsTestCases",
+      "options": [
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        },
+        {
+          "exclude-annotation": "org.junit.Ignore"
+        }
+      ]
+    },
+    {
+      "name": "CtsSecureFrpInstallTestCases",
+      "options": [
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        },
+        {
+          "exclude-annotation": "org.junit.Ignore"
+        }
+      ]
+    },
+    {
+      "name": "CtsSuspendAppsPermissionTestCases",
+      "options": [
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        },
+        {
+          "exclude-annotation": "org.junit.Ignore"
+        }
+      ]
     }
   ],
   "postsubmit": [
diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
index 16deaa0..f336672 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
@@ -21,6 +21,7 @@
 import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK;
 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST;
 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK;
 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_ONLY_COREAPP_ALLOWED;
 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_RESOURCES_ARSC_COMPRESSED;
@@ -934,6 +935,13 @@
             );
         }
 
+        if (ParsedPermissionUtils.declareDuplicatePermission(pkg)) {
+            return input.error(
+                    INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                    "Declare duplicate permissions with different protection levels."
+            );
+        }
+
         convertCompatPermissions(pkg);
 
         convertSplitPermissions(pkg);
diff --git a/core/java/android/content/pm/parsing/component/ParsedPermissionUtils.java b/core/java/android/content/pm/parsing/component/ParsedPermissionUtils.java
index 66e9d3d..86c8f02 100644
--- a/core/java/android/content/pm/parsing/component/ParsedPermissionUtils.java
+++ b/core/java/android/content/pm/parsing/component/ParsedPermissionUtils.java
@@ -27,6 +27,7 @@
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
+import android.util.ArrayMap;
 import android.util.Slog;
 
 import com.android.internal.R;
@@ -34,6 +35,7 @@
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
+import java.util.List;
 
 /** @hide */
 public class ParsedPermissionUtils {
@@ -271,4 +273,29 @@
         }
         return size;
     }
+
+    /**
+     * @return {@code true} if the package declares duplicate permissions with different
+     * protection levels.
+     */
+    public static boolean declareDuplicatePermission(@NonNull ParsingPackage pkg) {
+        final List<ParsedPermission> permissions = pkg.getPermissions();
+        final int size = permissions.size();
+        if (size > 0) {
+            final ArrayMap<String, ParsedPermission> checkDuplicatePerm = new ArrayMap<>(size);
+            for (int i = 0; i < size; i++) {
+                final ParsedPermission parsedPermission = permissions.get(i);
+                final String name = parsedPermission.getName();
+                final ParsedPermission perm = checkDuplicatePerm.get(name);
+                // Since a permission tree is also added as a permission with normal protection
+                // level, we need to skip if the parsedPermission is a permission tree.
+                if (perm != null && !(perm.isTree() || parsedPermission.isTree())
+                        && perm.getProtectionLevel() != parsedPermission.getProtectionLevel()) {
+                    return true;
+                }
+                checkDuplicatePerm.put(name, parsedPermission);
+            }
+        }
+        return false;
+    }
 }
diff --git a/core/java/android/database/AbstractCursor.java b/core/java/android/database/AbstractCursor.java
index cf25c3c..69d573f 100644
--- a/core/java/android/database/AbstractCursor.java
+++ b/core/java/android/database/AbstractCursor.java
@@ -224,7 +224,7 @@
     /* Implementation */
     public AbstractCursor() {
         mPos = -1;
-        mCloseGuard.open("close");
+        mCloseGuard.open("AbstractCursor.close");
     }
 
     @Override
diff --git a/core/java/android/database/CursorWindow.java b/core/java/android/database/CursorWindow.java
index ccb7cf1..f13c795 100644
--- a/core/java/android/database/CursorWindow.java
+++ b/core/java/android/database/CursorWindow.java
@@ -142,7 +142,7 @@
         if (mWindowPtr == 0) {
             throw new AssertionError(); // Not possible, the native code won't return it.
         }
-        mCloseGuard.open("close");
+        mCloseGuard.open("CursorWindow.close");
     }
 
     /**
@@ -170,7 +170,7 @@
             throw new AssertionError(); // Not possible, the native code won't return it.
         }
         mName = nativeGetName(mWindowPtr);
-        mCloseGuard.open("close");
+        mCloseGuard.open("CursorWindow.close");
     }
 
     @Override
diff --git a/core/java/android/database/sqlite/SQLiteConnection.java b/core/java/android/database/sqlite/SQLiteConnection.java
index 328858b..6d6ec06 100644
--- a/core/java/android/database/sqlite/SQLiteConnection.java
+++ b/core/java/android/database/sqlite/SQLiteConnection.java
@@ -179,7 +179,7 @@
         mIsReadOnlyConnection = mConfiguration.isReadOnlyDatabase();
         mPreparedStatementCache = new PreparedStatementCache(
                 mConfiguration.maxSqlCacheSize);
-        mCloseGuard.open("close");
+        mCloseGuard.open("SQLiteConnection.close");
     }
 
     @Override
diff --git a/core/java/android/database/sqlite/SQLiteConnectionPool.java b/core/java/android/database/sqlite/SQLiteConnectionPool.java
index d3ad6bb..216c9c2 100644
--- a/core/java/android/database/sqlite/SQLiteConnectionPool.java
+++ b/core/java/android/database/sqlite/SQLiteConnectionPool.java
@@ -218,7 +218,7 @@
 
         // Mark the pool as being open for business.
         mIsOpen = true;
-        mCloseGuard.open("close");
+        mCloseGuard.open("SQLiteConnectionPool.close");
     }
 
     /**
diff --git a/core/java/android/hardware/HardwareBuffer.java b/core/java/android/hardware/HardwareBuffer.java
index a4a8f31..4683d25 100644
--- a/core/java/android/hardware/HardwareBuffer.java
+++ b/core/java/android/hardware/HardwareBuffer.java
@@ -253,7 +253,7 @@
         NativeAllocationRegistry registry = new NativeAllocationRegistry(
                 loader, nGetNativeFinalizer(), bufferSize);
         mCleaner = registry.registerNativeAllocation(this, mNativeObject);
-        mCloseGuard.open("close");
+        mCloseGuard.open("HardwareBuffer.close");
     }
 
     @Override
diff --git a/core/java/android/hardware/SystemSensorManager.java b/core/java/android/hardware/SystemSensorManager.java
index e9fffa3..3a8513b 100644
--- a/core/java/android/hardware/SystemSensorManager.java
+++ b/core/java/android/hardware/SystemSensorManager.java
@@ -464,7 +464,8 @@
 
             IntentFilter filter = new IntentFilter("dynamic_sensor_change");
             filter.addAction(Intent.ACTION_DYNAMIC_SENSOR_CHANGED);
-            mContext.registerReceiver(mDynamicSensorBroadcastReceiver, filter);
+            mContext.registerReceiver(mDynamicSensorBroadcastReceiver, filter,
+                    Context.RECEIVER_NOT_EXPORTED);
         }
     }
 
@@ -687,7 +688,7 @@
                     new WeakReference<>(this), looper.getQueue(),
                     packageName, mode, manager.mContext.getOpPackageName(),
                     manager.mContext.getAttributionTag());
-            mCloseGuard.open("dispose");
+            mCloseGuard.open("BaseEventQueue.dispose");
             mManager = manager;
         }
 
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index 01833fd..e731165 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -965,7 +965,7 @@
 
     private static final class DisplayListenerDelegate extends Handler {
         public final DisplayListener mListener;
-        public long mEventsMask;
+        public volatile long mEventsMask;
 
         private final DisplayInfo mDisplayInfo = new DisplayInfo();
 
@@ -985,12 +985,12 @@
             removeCallbacksAndMessages(null);
         }
 
-        public synchronized void setEventsMask(@EventsMask long newEventsMask) {
+        public void setEventsMask(@EventsMask long newEventsMask) {
             mEventsMask = newEventsMask;
         }
 
         @Override
-        public synchronized void handleMessage(Message msg) {
+        public void handleMessage(Message msg) {
             switch (msg.what) {
                 case EVENT_DISPLAY_ADDED:
                     if ((mEventsMask & DisplayManager.EVENT_FLAG_DISPLAY_ADDED) != 0) {
diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl
index 19fb845..2ac194b 100644
--- a/core/java/android/hardware/input/IInputManager.aidl
+++ b/core/java/android/hardware/input/IInputManager.aidl
@@ -144,4 +144,6 @@
     void openLightSession(int deviceId, String opPkg, in IBinder token);
 
     void closeLightSession(int deviceId, in IBinder token);
+
+    void cancelCurrentTouch();
 }
diff --git a/core/java/android/hardware/input/InputDeviceLightsManager.java b/core/java/android/hardware/input/InputDeviceLightsManager.java
index 885df7b..802e6dd 100644
--- a/core/java/android/hardware/input/InputDeviceLightsManager.java
+++ b/core/java/android/hardware/input/InputDeviceLightsManager.java
@@ -100,7 +100,7 @@
          * Instantiated by {@link LightsManager#openSession()}.
          */
         private InputDeviceLightsSession() {
-            mCloseGuard.open("close");
+            mCloseGuard.open("InputDeviceLightsSession.close");
         }
 
         /**
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index 6f0c944..6253fb9 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -1650,6 +1650,18 @@
     }
 
     /**
+     * Cancel all ongoing pointer gestures on all displays.
+     * @hide
+     */
+    public void cancelCurrentTouch() {
+        try {
+            mIm.cancelCurrentTouch();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Listens for changes in input devices.
      */
     public interface InputDeviceListener {
diff --git a/core/java/android/hardware/lights/SystemLightsManager.java b/core/java/android/hardware/lights/SystemLightsManager.java
index d0df611..055a7f4 100644
--- a/core/java/android/hardware/lights/SystemLightsManager.java
+++ b/core/java/android/hardware/lights/SystemLightsManager.java
@@ -145,7 +145,7 @@
          */
         @RequiresPermission(Manifest.permission.CONTROL_DEVICE_LIGHTS)
         private SystemLightsSession() {
-            mCloseGuard.open("close");
+            mCloseGuard.open("SystemLightsSession.close");
         }
 
         /**
diff --git a/core/java/android/hardware/location/ContextHubClient.java b/core/java/android/hardware/location/ContextHubClient.java
index a525f58..9468ca2 100644
--- a/core/java/android/hardware/location/ContextHubClient.java
+++ b/core/java/android/hardware/location/ContextHubClient.java
@@ -30,7 +30,7 @@
 
 /**
  * A class describing a client of the Context Hub Service.
- *
+ * <p>
  * Clients can send messages to nanoapps at a Context Hub through this object. The APIs supported
  * by this object are thread-safe and can be used without external synchronization.
  *
@@ -69,7 +69,7 @@
             mCloseGuard = null;
         } else {
             mCloseGuard = CloseGuard.get();
-            mCloseGuard.open("close");
+            mCloseGuard.open("ContextHubClient.close");
         }
     }
 
@@ -110,7 +110,7 @@
      * This value can be used as an identifier for the messaging channel between a
      * ContextHubClient and the Context Hub. This may be used as a routing mechanism
      * between various ContextHubClient objects within an application.
-     *
+     * <p>
      * The value returned by this method will remain the same if it is associated with
      * the same client reference at the ContextHubService (for instance, the ID of a
      * PendingIntent ContextHubClient will remain the same even if the local object
@@ -119,8 +119,6 @@
      * of a non-equal PendingIntent client), the ID will not be the same.
      *
      * @return The ID of this ContextHubClient.
-     *
-     * @throws IllegalStateException if the ID was not set internally.
      */
     public int getId() {
         if (mId == null) {
@@ -135,7 +133,7 @@
      * When this function is invoked, the messaging associated with this client is invalidated.
      * All futures messages targeted for this client are dropped at the service, and the
      * ContextHubClient is unregistered from the service.
-     *
+     * <p>
      * If this object has a PendingIntent, i.e. the object was generated via
      * {@link ContextHubManager.createClient(PendingIntent, ContextHubInfo, long)}, then the
      * Intent events corresponding to the PendingIntent will no longer be triggered.
@@ -158,7 +156,7 @@
      *
      * This function returns RESULT_SUCCESS if the message has reached the HAL, but
      * does not guarantee delivery of the message to the target nanoapp.
-     *
+     * <p>
      * Before sending the first message to your nanoapp, it's recommended that the following
      * operations should be performed:
      * 1) Invoke {@link ContextHubManager#queryNanoApps(ContextHubInfo)} to verify the nanoapp is
diff --git a/core/java/android/hardware/usb/UsbDeviceConnection.java b/core/java/android/hardware/usb/UsbDeviceConnection.java
index 1c35cb6..60d8cac 100644
--- a/core/java/android/hardware/usb/UsbDeviceConnection.java
+++ b/core/java/android/hardware/usb/UsbDeviceConnection.java
@@ -69,7 +69,7 @@
             boolean wasOpened = native_open(name, pfd.getFileDescriptor());
 
             if (wasOpened) {
-                mCloseGuard.open("close");
+                mCloseGuard.open("UsbDeviceConnection.close");
             }
 
             return wasOpened;
diff --git a/core/java/android/hardware/usb/UsbRequest.java b/core/java/android/hardware/usb/UsbRequest.java
index d1c6465d..6ac5e8d 100644
--- a/core/java/android/hardware/usb/UsbRequest.java
+++ b/core/java/android/hardware/usb/UsbRequest.java
@@ -103,7 +103,7 @@
                 endpoint.getAttributes(), endpoint.getMaxPacketSize(), endpoint.getInterval());
 
         if (wasInitialized) {
-            mCloseGuard.open("close");
+            mCloseGuard.open("UsbRequest.close");
         }
 
         return wasInitialized;
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 22b444e..afaa085 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -51,7 +51,6 @@
 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
 import static android.view.WindowInsets.Type.navigationBars;
 import static android.view.WindowInsets.Type.statusBars;
-import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
 
 import static java.lang.annotation.RetentionPolicy.SOURCE;
 
@@ -1340,28 +1339,43 @@
         mInflater = (LayoutInflater)getSystemService(
                 Context.LAYOUT_INFLATER_SERVICE);
         Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.initSoftInputWindow");
-        mWindow = new SoftInputWindow(this, "InputMethod", mTheme, null, null, mDispatcherState,
-                WindowManager.LayoutParams.TYPE_INPUT_METHOD, Gravity.BOTTOM, false);
-        mWindow.getWindow().getAttributes().setFitInsetsTypes(statusBars() | navigationBars());
-        mWindow.getWindow().getAttributes().setFitInsetsSides(Side.all() & ~Side.BOTTOM);
-        mWindow.getWindow().getAttributes().receiveInsetsIgnoringZOrder = true;
+        mWindow = new SoftInputWindow(this, mTheme, mDispatcherState);
 
-        // Automotive devices may request the navigation bar to be hidden when the IME shows up
-        // (controlled via config_automotiveHideNavBarForKeyboard) in order to maximize the visible
-        // screen real estate. When this happens, the IME window should animate from the bottom of
-        // the screen to reduce the jank that happens from the lack of synchronization between the
-        // bottom system window and the IME window.
-        if (mIsAutomotive && mAutomotiveHideNavBarForKeyboard) {
-            mWindow.getWindow().setDecorFitsSystemWindows(false);
+        {
+            final Window window = mWindow.getWindow();
+            {
+                final WindowManager.LayoutParams lp = window.getAttributes();
+                lp.setTitle("InputMethod");
+                lp.type = WindowManager.LayoutParams.TYPE_INPUT_METHOD;
+                lp.width = WindowManager.LayoutParams.MATCH_PARENT;
+                lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
+                lp.gravity = Gravity.BOTTOM;
+                lp.setFitInsetsTypes(statusBars() | navigationBars());
+                lp.setFitInsetsSides(Side.all() & ~Side.BOTTOM);
+                lp.receiveInsetsIgnoringZOrder = true;
+                window.setAttributes(lp);
+            }
+
+            // For ColorView in DecorView to work, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS needs to be set
+            // by default (but IME developers can opt this out later if they want a new behavior).
+            final int windowFlags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+                    | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+                    | WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+            final int windowFlagsMask = windowFlags
+                    | WindowManager.LayoutParams.FLAG_DIM_BEHIND;  // to be unset
+            window.setFlags(windowFlags, windowFlagsMask);
+
+            // Automotive devices may request the navigation bar to be hidden when the IME shows up
+            // (controlled via config_automotiveHideNavBarForKeyboard) in order to maximize the
+            // visible screen real estate. When this happens, the IME window should animate from the
+            // bottom of the screen to reduce the jank that happens from the lack of synchronization
+            // between the bottom system window and the IME window.
+            if (mIsAutomotive && mAutomotiveHideNavBarForKeyboard) {
+                window.setDecorFitsSystemWindows(false);
+            }
         }
 
-        // For ColorView in DecorView to work, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS needs to be set
-        // by default (but IME developers can opt this out later if they want a new behavior).
-        mWindow.getWindow().setFlags(
-                FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
-
         initViews();
-        mWindow.getWindow().setLayout(MATCH_PARENT, WRAP_CONTENT);
         Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
 
         mInlineSuggestionSessionController = new InlineSuggestionSessionController(
diff --git a/core/java/android/inputmethodservice/SoftInputWindow.java b/core/java/android/inputmethodservice/SoftInputWindow.java
index bc0b37e..6c8eb41 100644
--- a/core/java/android/inputmethodservice/SoftInputWindow.java
+++ b/core/java/android/inputmethodservice/SoftInputWindow.java
@@ -1,27 +1,23 @@
 /*
- * Copyright (C) 2007-2008 The Android Open Source Project
- * 
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- * 
- * http://www.apache.org/licenses/LICENSE-2.0
- * 
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
  * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
  */
 
 package android.inputmethodservice;
 
 import static android.inputmethodservice.SoftInputWindowProto.BOUNDS;
-import static android.inputmethodservice.SoftInputWindowProto.GRAVITY;
-import static android.inputmethodservice.SoftInputWindowProto.NAME;
-import static android.inputmethodservice.SoftInputWindowProto.TAKES_FOCUS;
 import static android.inputmethodservice.SoftInputWindowProto.WINDOW_STATE;
-import static android.inputmethodservice.SoftInputWindowProto.WINDOW_TYPE;
 
 import static java.lang.annotation.RetentionPolicy.SOURCE;
 
@@ -33,7 +29,6 @@
 import android.os.IBinder;
 import android.util.Log;
 import android.util.proto.ProtoOutputStream;
-import android.view.Gravity;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.View;
@@ -42,29 +37,22 @@
 import java.lang.annotation.Retention;
 
 /**
- * A SoftInputWindow is a Dialog that is intended to be used for a top-level input
- * method window.  It will be displayed along the edge of the screen, moving
- * the application user interface away from it so that the focused item is
- * always visible.
- * @hide
+ * A {@link SoftInputWindow} is a {@link Dialog} that is intended to be used for a top-level input
+ * method window.  It will be displayed along the edge of the screen, moving the application user
+ * interface away from it so that the focused item is always visible.
  */
-public class SoftInputWindow extends Dialog {
+final class SoftInputWindow extends Dialog {
     private static final boolean DEBUG = false;
     private static final String TAG = "SoftInputWindow";
 
-    final String mName;
-    final Callback mCallback;
-    final KeyEvent.Callback mKeyEventCallback;
-    final KeyEvent.DispatcherState mDispatcherState;
-    final int mWindowType;
-    final int mGravity;
-    final boolean mTakesFocus;
+    private final KeyEvent.DispatcherState mDispatcherState;
     private final Rect mBounds = new Rect();
 
     @Retention(SOURCE)
-    @IntDef(value = {SoftInputWindowState.TOKEN_PENDING, SoftInputWindowState.TOKEN_SET,
-            SoftInputWindowState.SHOWN_AT_LEAST_ONCE, SoftInputWindowState.REJECTED_AT_LEAST_ONCE})
-    private @interface SoftInputWindowState {
+    @IntDef(value = {WindowState.TOKEN_PENDING, WindowState.TOKEN_SET,
+            WindowState.SHOWN_AT_LEAST_ONCE, WindowState.REJECTED_AT_LEAST_ONCE,
+            WindowState.DESTROYED})
+    private @interface WindowState {
         /**
          * The window token is not set yet.
          */
@@ -88,21 +76,23 @@
         int DESTROYED = 4;
     }
 
-    @SoftInputWindowState
-    private int mWindowState = SoftInputWindowState.TOKEN_PENDING;
+    @WindowState
+    private int mWindowState = WindowState.TOKEN_PENDING;
 
-    public interface Callback {
-        public void onBackPressed();
-    }
-
-    public void setToken(IBinder token) {
+    /**
+     * Set {@link IBinder} window token to the window.
+     *
+     * <p>This method can be called only once.</p>
+     * @param token {@link IBinder} token to be associated with the window.
+     */
+    void setToken(IBinder token) {
         switch (mWindowState) {
-            case SoftInputWindowState.TOKEN_PENDING:
+            case WindowState.TOKEN_PENDING:
                 // Normal scenario.  Nothing to worry about.
                 WindowManager.LayoutParams lp = getWindow().getAttributes();
                 lp.token = token;
                 getWindow().setAttributes(lp);
-                updateWindowState(SoftInputWindowState.TOKEN_SET);
+                updateWindowState(WindowState.TOKEN_SET);
 
                 // As soon as we have a token, make sure the window is added (but not shown) by
                 // setting visibility to INVISIBLE and calling show() on Dialog. Note that
@@ -111,11 +101,11 @@
                 getWindow().getDecorView().setVisibility(View.INVISIBLE);
                 show();
                 return;
-            case SoftInputWindowState.TOKEN_SET:
-            case SoftInputWindowState.SHOWN_AT_LEAST_ONCE:
-            case SoftInputWindowState.REJECTED_AT_LEAST_ONCE:
+            case WindowState.TOKEN_SET:
+            case WindowState.SHOWN_AT_LEAST_ONCE:
+            case WindowState.REJECTED_AT_LEAST_ONCE:
                 throw new IllegalStateException("setToken can be called only once");
-            case SoftInputWindowState.DESTROYED:
+            case WindowState.DESTROYED:
                 // Just ignore.  Since there are multiple event queues from the token is issued
                 // in the system server to the timing when it arrives here, it can be delivered
                 // after the is already destroyed.  No one should be blamed because of such an
@@ -129,7 +119,7 @@
 
     /**
      * Create a SoftInputWindow that uses a custom style.
-     * 
+     *
      * @param context The Context in which the DockWindow should run. In
      *        particular, it uses the window manager and theme from this context
      *        to present its UI.
@@ -139,18 +129,9 @@
      *        using styles. This theme is applied on top of the current theme in
      *        <var>context</var>. If 0, the default dialog theme will be used.
      */
-    public SoftInputWindow(Context context, String name, int theme, Callback callback,
-            KeyEvent.Callback keyEventCallback, KeyEvent.DispatcherState dispatcherState,
-            int windowType, int gravity, boolean takesFocus) {
+    SoftInputWindow(Context context, int theme, KeyEvent.DispatcherState dispatcherState) {
         super(context, theme);
-        mName = name;
-        mCallback = callback;
-        mKeyEventCallback = keyEventCallback;
         mDispatcherState = dispatcherState;
-        mWindowType = windowType;
-        mGravity = gravity;
-        mTakesFocus = takesFocus;
-        initDockWindow();
     }
 
     @Override
@@ -175,108 +156,17 @@
         }
     }
 
-    /**
-     * Set which boundary of the screen the DockWindow sticks to.
-     * 
-     * @param gravity The boundary of the screen to stick. See {@link
-     *        android.view.Gravity.LEFT}, {@link android.view.Gravity.TOP},
-     *        {@link android.view.Gravity.BOTTOM}, {@link
-     *        android.view.Gravity.RIGHT}.
-     */
-    public void setGravity(int gravity) {
-        WindowManager.LayoutParams lp = getWindow().getAttributes();
-        lp.gravity = gravity;
-        updateWidthHeight(lp);
-        getWindow().setAttributes(lp);
-    }
-
-    public int getGravity() {
-        return getWindow().getAttributes().gravity;
-    }
-
-    private void updateWidthHeight(WindowManager.LayoutParams lp) {
-        if (lp.gravity == Gravity.TOP || lp.gravity == Gravity.BOTTOM) {
-            lp.width = WindowManager.LayoutParams.MATCH_PARENT;
-            lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
-        } else {
-            lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
-            lp.height = WindowManager.LayoutParams.MATCH_PARENT;
-        }
-    }
-
-    public boolean onKeyDown(int keyCode, KeyEvent event) {
-        if (mKeyEventCallback != null && mKeyEventCallback.onKeyDown(keyCode, event)) {
-            return true;
-        }
-        return super.onKeyDown(keyCode, event);
-    }
-
-    public boolean onKeyLongPress(int keyCode, KeyEvent event) {
-        if (mKeyEventCallback != null && mKeyEventCallback.onKeyLongPress(keyCode, event)) {
-            return true;
-        }
-        return super.onKeyLongPress(keyCode, event);
-    }
-
-    public boolean onKeyUp(int keyCode, KeyEvent event) {
-        if (mKeyEventCallback != null && mKeyEventCallback.onKeyUp(keyCode, event)) {
-            return true;
-        }
-        return super.onKeyUp(keyCode, event);
-    }
-
-    public boolean onKeyMultiple(int keyCode, int count, KeyEvent event) {
-        if (mKeyEventCallback != null && mKeyEventCallback.onKeyMultiple(keyCode, count, event)) {
-            return true;
-        }
-        return super.onKeyMultiple(keyCode, count, event);
-    }
-
-    public void onBackPressed() {
-        if (mCallback != null) {
-            mCallback.onBackPressed();
-        } else {
-            super.onBackPressed();
-        }
-    }
-
-    private void initDockWindow() {
-        WindowManager.LayoutParams lp = getWindow().getAttributes();
-
-        lp.type = mWindowType;
-        lp.setTitle(mName);
-
-        lp.gravity = mGravity;
-        updateWidthHeight(lp);
-
-        getWindow().setAttributes(lp);
-
-        int windowSetFlags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
-        int windowModFlags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN |
-                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
-                WindowManager.LayoutParams.FLAG_DIM_BEHIND;
-
-        if (!mTakesFocus) {
-            windowSetFlags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
-        } else {
-            windowSetFlags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
-            windowModFlags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
-        }
-
-        getWindow().setFlags(windowSetFlags, windowModFlags);
-    }
-
     @Override
-    public final void show() {
+    public void show() {
         switch (mWindowState) {
-            case SoftInputWindowState.TOKEN_PENDING:
+            case WindowState.TOKEN_PENDING:
                 throw new IllegalStateException("Window token is not set yet.");
-            case SoftInputWindowState.TOKEN_SET:
-            case SoftInputWindowState.SHOWN_AT_LEAST_ONCE:
+            case WindowState.TOKEN_SET:
+            case WindowState.SHOWN_AT_LEAST_ONCE:
                 // Normal scenario.  Nothing to worry about.
                 try {
                     super.show();
-                    updateWindowState(SoftInputWindowState.SHOWN_AT_LEAST_ONCE);
+                    updateWindowState(WindowState.SHOWN_AT_LEAST_ONCE);
                 } catch (WindowManager.BadTokenException e) {
                     // Just ignore this exception.  Since show() can be requested from other
                     // components such as the system and there could be multiple event queues before
@@ -286,14 +176,14 @@
                     // the state so that we do not touch this window later.
                     Log.i(TAG, "Probably the IME window token is already invalidated."
                             + " show() does nothing.");
-                    updateWindowState(SoftInputWindowState.REJECTED_AT_LEAST_ONCE);
+                    updateWindowState(WindowState.REJECTED_AT_LEAST_ONCE);
                 }
                 return;
-            case SoftInputWindowState.REJECTED_AT_LEAST_ONCE:
+            case WindowState.REJECTED_AT_LEAST_ONCE:
                 // Just ignore.  In general we cannot completely avoid this kind of race condition.
                 Log.i(TAG, "Not trying to call show() because it was already rejected once.");
                 return;
-            case SoftInputWindowState.DESTROYED:
+            case WindowState.DESTROYED:
                 // Just ignore.  In general we cannot completely avoid this kind of race condition.
                 Log.i(TAG, "Ignoring show() because the window is already destroyed.");
                 return;
@@ -302,14 +192,14 @@
         }
     }
 
-    final void dismissForDestroyIfNecessary() {
+    void dismissForDestroyIfNecessary() {
         switch (mWindowState) {
-            case SoftInputWindowState.TOKEN_PENDING:
-            case SoftInputWindowState.TOKEN_SET:
+            case WindowState.TOKEN_PENDING:
+            case WindowState.TOKEN_SET:
                 // nothing to do because the window has never been shown.
-                updateWindowState(SoftInputWindowState.DESTROYED);
+                updateWindowState(WindowState.DESTROYED);
                 return;
-            case SoftInputWindowState.SHOWN_AT_LEAST_ONCE:
+            case WindowState.SHOWN_AT_LEAST_ONCE:
                 // Disable exit animation for the current IME window
                 // to avoid the race condition between the exit and enter animations
                 // when the current IME is being switched to another one.
@@ -327,16 +217,16 @@
                             + "No need to dismiss it.");
                 }
                 // Either way, consider that the window is destroyed.
-                updateWindowState(SoftInputWindowState.DESTROYED);
+                updateWindowState(WindowState.DESTROYED);
                 return;
-            case SoftInputWindowState.REJECTED_AT_LEAST_ONCE:
+            case WindowState.REJECTED_AT_LEAST_ONCE:
                 // Just ignore.  In general we cannot completely avoid this kind of race condition.
                 Log.i(TAG,
                         "Not trying to dismiss the window because it is most likely unnecessary.");
                 // Anyway, consider that the window is destroyed.
-                updateWindowState(SoftInputWindowState.DESTROYED);
+                updateWindowState(WindowState.DESTROYED);
                 return;
-            case SoftInputWindowState.DESTROYED:
+            case WindowState.DESTROYED:
                 throw new IllegalStateException(
                         "dismissForDestroyIfNecessary can be called only once");
             default:
@@ -344,7 +234,7 @@
         }
     }
 
-    private void updateWindowState(@SoftInputWindowState int newState) {
+    private void updateWindowState(@WindowState int newState) {
         if (DEBUG) {
             if (mWindowState != newState) {
                 Log.d(TAG, "WindowState: " + stateToString(mWindowState) + " -> "
@@ -354,17 +244,17 @@
         mWindowState = newState;
     }
 
-    private static String stateToString(@SoftInputWindowState int state) {
+    private static String stateToString(@WindowState int state) {
         switch (state) {
-            case SoftInputWindowState.TOKEN_PENDING:
+            case WindowState.TOKEN_PENDING:
                 return "TOKEN_PENDING";
-            case SoftInputWindowState.TOKEN_SET:
+            case WindowState.TOKEN_SET:
                 return "TOKEN_SET";
-            case SoftInputWindowState.SHOWN_AT_LEAST_ONCE:
+            case WindowState.SHOWN_AT_LEAST_ONCE:
                 return "SHOWN_AT_LEAST_ONCE";
-            case SoftInputWindowState.REJECTED_AT_LEAST_ONCE:
+            case WindowState.REJECTED_AT_LEAST_ONCE:
                 return "REJECTED_AT_LEAST_ONCE";
-            case SoftInputWindowState.DESTROYED:
+            case WindowState.DESTROYED:
                 return "DESTROYED";
             default:
                 throw new IllegalStateException("Unknown state=" + state);
@@ -373,10 +263,6 @@
 
     void dumpDebug(ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
-        proto.write(NAME, mName);
-        proto.write(WINDOW_TYPE, mWindowType);
-        proto.write(GRAVITY, mGravity);
-        proto.write(TAKES_FOCUS, mTakesFocus);
         mBounds.dumpDebug(proto, BOUNDS);
         proto.write(WINDOW_STATE, mWindowState);
         proto.end(token);
diff --git a/core/java/android/net/IInternalNetworkManagementListener.aidl b/core/java/android/net/IInternalNetworkManagementListener.aidl
new file mode 100644
index 0000000..69cde3b
--- /dev/null
+++ b/core/java/android/net/IInternalNetworkManagementListener.aidl
@@ -0,0 +1,25 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.net.InternalNetworkManagementException;
+import android.net.Network;
+
+/** @hide */
+oneway interface IInternalNetworkManagementListener {
+    void onComplete(in Network network, in InternalNetworkManagementException exception);
+}
\ No newline at end of file
diff --git a/core/java/android/net/Ikev2VpnProfile.java b/core/java/android/net/Ikev2VpnProfile.java
index b18e9be..fab692c 100644
--- a/core/java/android/net/Ikev2VpnProfile.java
+++ b/core/java/android/net/Ikev2VpnProfile.java
@@ -142,8 +142,9 @@
             boolean isBypassable,
             boolean isMetered,
             int maxMtu,
-            boolean restrictToTestNetworks) {
-        super(type);
+            boolean restrictToTestNetworks,
+            boolean excludeLocalRoutes) {
+        super(type, excludeLocalRoutes);
 
         checkNotNull(serverAddr, MISSING_PARAM_MSG_TMPL, "Server address");
         checkNotNull(userIdentity, MISSING_PARAM_MSG_TMPL, "User Identity");
@@ -403,7 +404,8 @@
                 && mIsBypassable == other.mIsBypassable
                 && mIsMetered == other.mIsMetered
                 && mMaxMtu == other.mMaxMtu
-                && mIsRestrictedToTestNetworks == other.mIsRestrictedToTestNetworks;
+                && mIsRestrictedToTestNetworks == other.mIsRestrictedToTestNetworks
+                && mExcludeLocalRoutes == other.mExcludeLocalRoutes;
     }
 
     /**
@@ -417,7 +419,7 @@
     @NonNull
     public VpnProfile toVpnProfile() throws IOException, GeneralSecurityException {
         final VpnProfile profile = new VpnProfile("" /* Key; value unused by IKEv2VpnProfile(s) */,
-                mIsRestrictedToTestNetworks);
+                mIsRestrictedToTestNetworks, mExcludeLocalRoutes);
         profile.type = mType;
         profile.server = mServerAddr;
         profile.ipsecIdentifier = mUserIdentity;
@@ -518,6 +520,8 @@
                 throw new IllegalArgumentException("Invalid auth method set");
         }
 
+        builder.setExcludeLocalRoutes(profile.excludeLocalRoutes);
+
         return builder.build();
     }
 
@@ -657,6 +661,7 @@
         private boolean mIsMetered = true;
         private int mMaxMtu = PlatformVpnProfile.MAX_MTU_DEFAULT;
         private boolean mIsRestrictedToTestNetworks = false;
+        private boolean mExcludeLocalRoutes = false;
 
         /**
          * Creates a new builder with the basic parameters of an IKEv2/IPsec VPN.
@@ -902,6 +907,18 @@
         }
 
         /**
+         *  Sets whether the local traffic is exempted from the VPN.
+         *
+         *  @hide TODO(184750836): unhide once the implementation is completed
+         */
+        @NonNull
+        @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
+        public Builder setExcludeLocalRoutes(boolean excludeLocalRoutes) {
+            mExcludeLocalRoutes = excludeLocalRoutes;
+            return this;
+        }
+
+        /**
          * Validates, builds and provisions the VpnProfile.
          *
          * @throws IllegalArgumentException if any of the required keys or values were invalid
@@ -924,7 +941,8 @@
                     mIsBypassable,
                     mIsMetered,
                     mMaxMtu,
-                    mIsRestrictedToTestNetworks);
+                    mIsRestrictedToTestNetworks,
+                    mExcludeLocalRoutes);
         }
     }
 }
diff --git a/telephony/java/com/android/internal/telephony/euicc/IResultCallback.aidl b/core/java/android/net/InternalNetworkManagementException.aidl
similarity index 76%
copy from telephony/java/com/android/internal/telephony/euicc/IResultCallback.aidl
copy to core/java/android/net/InternalNetworkManagementException.aidl
index 69f479c..dcce706 100644
--- a/telephony/java/com/android/internal/telephony/euicc/IResultCallback.aidl
+++ b/core/java/android/net/InternalNetworkManagementException.aidl
@@ -13,11 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.internal.telephony.euicc;
 
-import android.content.Intent;
+ package android.net;
 
-/** @hide */
-oneway interface IResultCallback {
-    void onComplete(int resultCode, in Intent resultIntent);
-}
+ parcelable InternalNetworkManagementException;
\ No newline at end of file
diff --git a/core/java/android/net/InternalNetworkManagementException.java b/core/java/android/net/InternalNetworkManagementException.java
new file mode 100644
index 0000000..7f4e403
--- /dev/null
+++ b/core/java/android/net/InternalNetworkManagementException.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 android.net;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/** @hide */
+public final class InternalNetworkManagementException
+        extends RuntimeException implements Parcelable {
+
+    /* @hide */
+    public InternalNetworkManagementException(@NonNull final Throwable t) {
+        super(t);
+    }
+
+    private InternalNetworkManagementException(@NonNull final Parcel source) {
+        super(source.readString());
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeString(getCause().getMessage());
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @NonNull
+    public static final Parcelable.Creator<InternalNetworkManagementException> CREATOR =
+            new Parcelable.Creator<InternalNetworkManagementException>() {
+                @Override
+                public InternalNetworkManagementException[] newArray(int size) {
+                    return new InternalNetworkManagementException[size];
+                }
+
+                @Override
+                public InternalNetworkManagementException createFromParcel(@NonNull Parcel source) {
+                    return new InternalNetworkManagementException(source);
+                }
+            };
+}
diff --git a/telephony/java/com/android/internal/telephony/euicc/IResultCallback.aidl b/core/java/android/net/InternalNetworkUpdateRequest.aidl
similarity index 76%
copy from telephony/java/com/android/internal/telephony/euicc/IResultCallback.aidl
copy to core/java/android/net/InternalNetworkUpdateRequest.aidl
index 69f479c..da00cb9 100644
--- a/telephony/java/com/android/internal/telephony/euicc/IResultCallback.aidl
+++ b/core/java/android/net/InternalNetworkUpdateRequest.aidl
@@ -13,11 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.internal.telephony.euicc;
 
-import android.content.Intent;
+ package android.net;
 
-/** @hide */
-oneway interface IResultCallback {
-    void onComplete(int resultCode, in Intent resultIntent);
-}
+ parcelable InternalNetworkUpdateRequest;
\ No newline at end of file
diff --git a/core/java/android/net/InternalNetworkUpdateRequest.java b/core/java/android/net/InternalNetworkUpdateRequest.java
new file mode 100644
index 0000000..6f09383
--- /dev/null
+++ b/core/java/android/net/InternalNetworkUpdateRequest.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/** @hide */
+public final class InternalNetworkUpdateRequest implements Parcelable {
+    @NonNull
+    private final StaticIpConfiguration mIpConfig;
+    @Nullable
+    private final NetworkCapabilities mNetworkCapabilities;
+
+    @NonNull
+    public StaticIpConfiguration getIpConfig() {
+        return new StaticIpConfiguration(mIpConfig);
+    }
+
+    @NonNull
+    public NetworkCapabilities getNetworkCapabilities() {
+        return mNetworkCapabilities == null
+                ? null : new NetworkCapabilities(mNetworkCapabilities);
+    }
+
+    /** @hide */
+    public InternalNetworkUpdateRequest(@NonNull final StaticIpConfiguration ipConfig,
+            @Nullable final NetworkCapabilities networkCapabilities) {
+        Objects.requireNonNull(ipConfig);
+        mIpConfig = new StaticIpConfiguration(ipConfig);
+        if (null == networkCapabilities) {
+            mNetworkCapabilities = null;
+        } else {
+            mNetworkCapabilities = new NetworkCapabilities(networkCapabilities);
+        }
+    }
+
+    private InternalNetworkUpdateRequest(@NonNull final Parcel source) {
+        Objects.requireNonNull(source);
+        mIpConfig = StaticIpConfiguration.CREATOR.createFromParcel(source);
+        mNetworkCapabilities = NetworkCapabilities.CREATOR.createFromParcel(source);
+    }
+
+    @Override
+    public String toString() {
+        return "InternalNetworkUpdateRequest{"
+                + "mIpConfig=" + mIpConfig
+                + ", mNetworkCapabilities=" + mNetworkCapabilities + '}';
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        InternalNetworkUpdateRequest that = (InternalNetworkUpdateRequest) o;
+
+        return Objects.equals(that.getIpConfig(), mIpConfig)
+                && Objects.equals(that.getNetworkCapabilities(), mNetworkCapabilities);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mIpConfig, mNetworkCapabilities);
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        mIpConfig.writeToParcel(dest, flags);
+        mNetworkCapabilities.writeToParcel(dest, flags);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @NonNull
+    public static final Parcelable.Creator<InternalNetworkUpdateRequest> CREATOR =
+            new Parcelable.Creator<InternalNetworkUpdateRequest>() {
+                @Override
+                public InternalNetworkUpdateRequest[] newArray(int size) {
+                    return new InternalNetworkUpdateRequest[size];
+                }
+
+                @Override
+                public InternalNetworkUpdateRequest createFromParcel(@NonNull Parcel source) {
+                    return new InternalNetworkUpdateRequest(source);
+                }
+            };
+}
diff --git a/core/java/android/net/NetworkPolicy.java b/core/java/android/net/NetworkPolicy.java
index f33a035..596f431 100644
--- a/core/java/android/net/NetworkPolicy.java
+++ b/core/java/android/net/NetworkPolicy.java
@@ -18,9 +18,11 @@
 
 import static android.net.NetworkStats.METERED_ALL;
 import static android.net.NetworkStats.METERED_YES;
+import static android.net.NetworkTemplate.MATCH_BLUETOOTH;
 import static android.net.NetworkTemplate.MATCH_CARRIER;
+import static android.net.NetworkTemplate.MATCH_ETHERNET;
 import static android.net.NetworkTemplate.MATCH_MOBILE;
-import static android.net.NetworkTemplate.SUBSCRIBER_ID_MATCH_RULE_EXACT;
+import static android.net.NetworkTemplate.MATCH_WIFI;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -42,6 +44,7 @@
 import java.time.ZonedDateTime;
 import java.util.Iterator;
 import java.util.Objects;
+import java.util.Set;
 
 /**
  * Policy for networks matching a {@link NetworkTemplate}, including usage cycle
@@ -59,15 +62,16 @@
      * Initial Version of the NetworkTemplate backup serializer.
      */
     private static final int TEMPLATE_BACKUP_VERSION_1_INIT = 1;
+    private static final int TEMPLATE_BACKUP_VERSION_2_UNSUPPORTED = 2;
     /**
      * Version of the NetworkTemplate backup serializer that added carrier template support.
      */
-    private static final int TEMPLATE_BACKUP_VERSION_2_SUPPORT_CARRIER_TEMPLATE = 2;
+    private static final int TEMPLATE_BACKUP_VERSION_3_SUPPORT_CARRIER_TEMPLATE = 3;
     /**
      * Latest Version of the NetworkTemplate Backup Serializer.
      */
     private static final int TEMPLATE_BACKUP_VERSION_LATEST =
-            TEMPLATE_BACKUP_VERSION_2_SUPPORT_CARRIER_TEMPLATE;
+            TEMPLATE_BACKUP_VERSION_3_SUPPORT_CARRIER_TEMPLATE;
 
     public static final int CYCLE_NONE = -1;
     public static final long WARNING_DISABLED = -1;
@@ -324,7 +328,7 @@
 
     @NonNull
     private byte[] getNetworkTemplateBytesForBackup() throws IOException {
-        if (!template.isPersistable()) {
+        if (!isTemplatePersistable(this.template)) {
             Log.wtf(TAG, "Trying to backup non-persistable template: " + this);
         }
 
@@ -334,10 +338,10 @@
         out.writeInt(TEMPLATE_BACKUP_VERSION_LATEST);
 
         out.writeInt(template.getMatchRule());
-        BackupUtils.writeString(out, template.getSubscriberId());
-        BackupUtils.writeString(out, template.getNetworkId());
+        BackupUtils.writeString(out, template.getSubscriberIds().iterator().next());
+        BackupUtils.writeString(out, template.getWifiNetworkKeys().isEmpty()
+                ? null : template.getWifiNetworkKeys().iterator().next());
         out.writeInt(template.getMeteredness());
-        out.writeInt(template.getSubscriberIdMatchRule());
 
         return baos.toByteArray();
     }
@@ -346,36 +350,61 @@
     private static NetworkTemplate getNetworkTemplateFromBackup(DataInputStream in)
             throws IOException, BackupUtils.BadVersionException {
         int version = in.readInt();
-        if (version < TEMPLATE_BACKUP_VERSION_1_INIT || version > TEMPLATE_BACKUP_VERSION_LATEST) {
+        if (version < TEMPLATE_BACKUP_VERSION_1_INIT || version > TEMPLATE_BACKUP_VERSION_LATEST
+                || version == TEMPLATE_BACKUP_VERSION_2_UNSUPPORTED) {
             throw new BackupUtils.BadVersionException("Unknown Backup Serialization Version");
         }
 
         int matchRule = in.readInt();
         final String subscriberId = BackupUtils.readString(in);
-        final String networkId = BackupUtils.readString(in);
+        final String wifiNetworkKey = BackupUtils.readString(in);
 
         final int metered;
-        final int subscriberIdMatchRule;
-        if (version >= TEMPLATE_BACKUP_VERSION_2_SUPPORT_CARRIER_TEMPLATE) {
+        if (version >= TEMPLATE_BACKUP_VERSION_3_SUPPORT_CARRIER_TEMPLATE) {
             metered = in.readInt();
-            subscriberIdMatchRule = in.readInt();
         } else {
             // For backward compatibility, fill the missing filters from match rules.
-            metered = (matchRule == MATCH_MOBILE
-                    || matchRule == NetworkTemplate.MATCH_MOBILE_WILDCARD
-                    || matchRule == MATCH_CARRIER) ? METERED_YES : METERED_ALL;
-            subscriberIdMatchRule = SUBSCRIBER_ID_MATCH_RULE_EXACT;
+            metered = (matchRule == MATCH_MOBILE || matchRule == MATCH_CARRIER)
+                    ? METERED_YES : METERED_ALL;
         }
 
         try {
-            return new NetworkTemplate(matchRule,
-                    subscriberId, new String[]{subscriberId},
-                    networkId, metered, NetworkStats.ROAMING_ALL,
-                    NetworkStats.DEFAULT_NETWORK_ALL, NetworkTemplate.NETWORK_TYPE_ALL,
-                    NetworkTemplate.OEM_MANAGED_ALL, subscriberIdMatchRule);
+            final NetworkTemplate.Builder builder = new NetworkTemplate.Builder(matchRule)
+                    .setMeteredness(metered);
+            if (subscriberId != null) {
+                builder.setSubscriberIds(Set.of(subscriberId));
+            }
+            if (wifiNetworkKey != null) {
+                builder.setWifiNetworkKeys(Set.of(wifiNetworkKey));
+            }
+            return builder.build();
         } catch (IllegalArgumentException e) {
             throw new BackupUtils.BadVersionException(
                     "Restored network template contains unknown match rule " + matchRule, e);
         }
     }
+
+    /**
+     * Check if the template can be persisted into disk.
+     */
+    public static boolean isTemplatePersistable(@NonNull NetworkTemplate template) {
+        switch (template.getMatchRule()) {
+            case MATCH_BLUETOOTH:
+            case MATCH_ETHERNET:
+                return true;
+            case MATCH_CARRIER:
+            case MATCH_MOBILE:
+                return !template.getSubscriberIds().isEmpty();
+            case MATCH_WIFI:
+                if (template.getWifiNetworkKeys().isEmpty()
+                        && template.getSubscriberIds().isEmpty()) {
+                    return false;
+                }
+                return true;
+            default:
+                // Don't allow persistable for unknown types or legacy types such as
+                // MATCH_MOBILE_WILDCARD, MATCH_PROXY, etc.
+                return false;
+        }
+    }
 }
diff --git a/core/java/android/net/PlatformVpnProfile.java b/core/java/android/net/PlatformVpnProfile.java
index 445ec91..777a90c 100644
--- a/core/java/android/net/PlatformVpnProfile.java
+++ b/core/java/android/net/PlatformVpnProfile.java
@@ -66,15 +66,30 @@
     @PlatformVpnType protected final int mType;
 
     /** @hide */
-    PlatformVpnProfile(@PlatformVpnType int type) {
+    protected final boolean mExcludeLocalRoutes;
+
+    /** @hide */
+    PlatformVpnProfile(@PlatformVpnType int type, boolean excludeLocalRoutes) {
         mType = type;
+        mExcludeLocalRoutes = excludeLocalRoutes;
     }
+
     /** Returns the profile integer type. */
     @PlatformVpnType
     public final int getType() {
         return mType;
     }
 
+
+    /**
+     * Returns if the local traffic is exempted from the VPN.
+     *
+     * @hide TODO(184750836): unhide once the implementation is completed
+     */
+    public final boolean getExcludeLocalRoutes() {
+        return mExcludeLocalRoutes;
+    }
+
     /** Returns a type string describing the VPN profile type */
     @NonNull
     public final String getTypeString() {
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index fa209cc..520730f 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -3374,6 +3374,11 @@
     public abstract Map<String, ? extends Timer> getKernelWakelockStats();
 
     /**
+     * Returns aggregated wake lock stats.
+     */
+    public abstract WakeLockStats getWakeLockStats();
+
+    /**
      * Returns Timers tracking the total time of each Resource Power Manager state and voter.
      */
     public abstract Map<String, ? extends Timer> getRpmStats();
diff --git a/core/java/android/os/BatteryStatsManager.java b/core/java/android/os/BatteryStatsManager.java
index 7f526c1..6339435 100644
--- a/core/java/android/os/BatteryStatsManager.java
+++ b/core/java/android/os/BatteryStatsManager.java
@@ -157,6 +157,7 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface WifiSupplState {}
 
+
     private final IBatteryStats mBatteryStats;
 
     /** @hide */
@@ -352,6 +353,21 @@
     }
 
     /**
+     * Retrieves accumulate wake lock stats.
+     *
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.BATTERY_STATS)
+    @NonNull
+    public WakeLockStats getWakeLockStats() {
+        try {
+            return mBatteryStats.getWakeLockStats();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Indicates an app acquiring full wifi lock.
      *
      * @param ws worksource (to be used for battery blaming).
diff --git a/core/java/android/os/BatteryUsageStats.java b/core/java/android/os/BatteryUsageStats.java
index a23dae8..abe5f81 100644
--- a/core/java/android/os/BatteryUsageStats.java
+++ b/core/java/android/os/BatteryUsageStats.java
@@ -135,7 +135,7 @@
     private final List<UidBatteryConsumer> mUidBatteryConsumers;
     private final List<UserBatteryConsumer> mUserBatteryConsumers;
     private final AggregateBatteryConsumer[] mAggregateBatteryConsumers;
-    private final Parcel mHistoryBuffer;
+    private final BatteryStatsHistory mBatteryStatsHistory;
     private CursorWindow mBatteryConsumersCursorWindow;
 
     private BatteryUsageStats(@NonNull Builder builder) {
@@ -146,7 +146,7 @@
         mDischargePercentage = builder.mDischargePercentage;
         mDischargedPowerLowerBound = builder.mDischargedPowerLowerBoundMah;
         mDischargedPowerUpperBound = builder.mDischargedPowerUpperBoundMah;
-        mHistoryBuffer = builder.mHistoryBuffer;
+        mBatteryStatsHistory = builder.mBatteryStatsHistory;
         mBatteryTimeRemainingMs = builder.mBatteryTimeRemainingMs;
         mChargeTimeRemainingMs = builder.mChargeTimeRemainingMs;
         mCustomPowerComponentNames = builder.mCustomPowerComponentNames;
@@ -301,11 +301,11 @@
      */
     @NonNull
     public BatteryStatsHistoryIterator iterateBatteryStatsHistory() {
-        if (mHistoryBuffer == null) {
+        if (mBatteryStatsHistory == null) {
             throw new IllegalStateException(
                     "Battery history was not requested in the BatteryUsageStatsQuery");
         }
-        return new BatteryStatsHistoryIterator(new BatteryStatsHistory(mHistoryBuffer));
+        return new BatteryStatsHistoryIterator(mBatteryStatsHistory);
     }
 
     @Override
@@ -363,12 +363,9 @@
         }
 
         if (source.readBoolean()) {
-            final byte[] historyBlob = source.readBlob();
-
-            mHistoryBuffer = Parcel.obtain();
-            mHistoryBuffer.unmarshall(historyBlob, 0, historyBlob.length);
+            mBatteryStatsHistory = BatteryStatsHistory.createFromBatteryUsageStatsParcel(source);
         } else {
-            mHistoryBuffer = null;
+            mBatteryStatsHistory = null;
         }
     }
 
@@ -389,9 +386,9 @@
 
         mBatteryConsumersCursorWindow.writeToParcel(dest, flags);
 
-        if (mHistoryBuffer != null) {
+        if (mBatteryStatsHistory != null) {
             dest.writeBoolean(true);
-            dest.writeBlob(mHistoryBuffer.marshall());
+            mBatteryStatsHistory.writeToBatteryUsageStatsParcel(dest);
         } else {
             dest.writeBoolean(false);
         }
@@ -770,7 +767,7 @@
                 new SparseArray<>();
         private final SparseArray<UserBatteryConsumer.Builder> mUserBatteryConsumerBuilders =
                 new SparseArray<>();
-        private Parcel mHistoryBuffer;
+        private BatteryStatsHistory mBatteryStatsHistory;
 
         public Builder(@NonNull String[] customPowerComponentNames) {
             this(customPowerComponentNames, false, false);
@@ -895,8 +892,8 @@
          * Sets the parceled recent history.
          */
         @NonNull
-        public Builder setBatteryHistory(Parcel historyBuffer) {
-            mHistoryBuffer = historyBuffer;
+        public Builder setBatteryHistory(BatteryStatsHistory batteryStatsHistory) {
+            mBatteryStatsHistory = batteryStatsHistory;
             return this;
         }
 
diff --git a/core/java/android/os/OWNERS b/core/java/android/os/OWNERS
index 1e424d1..5d9f2189 100644
--- a/core/java/android/os/OWNERS
+++ b/core/java/android/os/OWNERS
@@ -10,9 +10,8 @@
 # BatteryStats
 per-file *BatteryConsumer* = file:/BATTERY_STATS_OWNERS
 per-file BatteryManager* = file:/BATTERY_STATS_OWNERS
-per-file BatteryStats* = file:/BATTERY_STATS_OWNERS
-per-file BatteryUsageStats* = file:/BATTERY_STATS_OWNERS
 per-file PowerComponents.java = file:/BATTERY_STATS_OWNERS
+per-file *Stats* = file:/BATTERY_STATS_OWNERS
 
 # Multiuser
 per-file IUser* = file:/MULTIUSER_OWNERS
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index dbb5a2c..70aaa5e 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -15,10 +15,13 @@
  */
 package android.os;
 
+import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
+
 import android.animation.ValueAnimator;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.app.ActivityManager;
 import android.app.ActivityThread;
@@ -2690,6 +2693,12 @@
         ((AndroidBlockGuardPolicy) policy).onCustomSlowCall(name);
     }
 
+    /** @hide */
+    @SystemApi(client = MODULE_LIBRARIES)
+    public static void noteUntaggedSocket() {
+        if (vmUntaggedSocketEnabled()) onUntaggedSocket();
+    }
+
     /**
      * For code to note that a resource was obtained using a type other than its defined type. This
      * is a no-op unless the current thread's {@link android.os.StrictMode.ThreadPolicy} has {@link
diff --git a/core/java/android/os/SystemClock.java b/core/java/android/os/SystemClock.java
index d8f6344..b9252d6 100644
--- a/core/java/android/os/SystemClock.java
+++ b/core/java/android/os/SystemClock.java
@@ -311,7 +311,6 @@
      * time or throw.
      *
      * @throws DateTimeException when no accurate network time can be provided.
-     * @hide
      */
     public static @NonNull Clock currentNetworkTimeClock() {
         return new SimpleClock(ZoneOffset.UTC) {
diff --git a/telephony/java/com/android/internal/telephony/euicc/IResultCallback.aidl b/core/java/android/os/WakeLockStats.aidl
similarity index 76%
copy from telephony/java/com/android/internal/telephony/euicc/IResultCallback.aidl
copy to core/java/android/os/WakeLockStats.aidl
index 69f479c..be08d78 100644
--- a/telephony/java/com/android/internal/telephony/euicc/IResultCallback.aidl
+++ b/core/java/android/os/WakeLockStats.aidl
@@ -13,11 +13,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.internal.telephony.euicc;
 
-import android.content.Intent;
+package android.os;
 
-/** @hide */
-oneway interface IResultCallback {
-    void onComplete(int resultCode, in Intent resultIntent);
-}
+/** {@hide} */
+parcelable WakeLockStats;
diff --git a/core/java/android/os/WakeLockStats.java b/core/java/android/os/WakeLockStats.java
new file mode 100644
index 0000000..05a7313
--- /dev/null
+++ b/core/java/android/os/WakeLockStats.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.annotation.NonNull;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Snapshot of wake lock stats.
+ *  @hide
+ */
+public final class WakeLockStats implements Parcelable {
+
+    /** @hide */
+    public static class WakeLock {
+        public final int uid;
+        @NonNull
+        public final String name;
+        public final int timesAcquired;
+        public final long totalTimeHeldMs;
+
+        /**
+         * Time in milliseconds that the lock has been held or 0 if not currently holding the lock
+         */
+        public final long timeHeldMs;
+
+        public WakeLock(int uid, @NonNull String name, int timesAcquired, long totalTimeHeldMs,
+                long timeHeldMs) {
+            this.uid = uid;
+            this.name = name;
+            this.timesAcquired = timesAcquired;
+            this.totalTimeHeldMs = totalTimeHeldMs;
+            this.timeHeldMs = timeHeldMs;
+        }
+
+        private WakeLock(Parcel in) {
+            uid = in.readInt();
+            name = in.readString();
+            timesAcquired = in.readInt();
+            totalTimeHeldMs = in.readLong();
+            timeHeldMs = in.readLong();
+        }
+
+        private void writeToParcel(Parcel out) {
+            out.writeInt(uid);
+            out.writeString(name);
+            out.writeInt(timesAcquired);
+            out.writeLong(totalTimeHeldMs);
+            out.writeLong(timeHeldMs);
+        }
+
+        @Override
+        public String toString() {
+            return "WakeLock{"
+                    + "uid=" + uid
+                    + ", name='" + name + '\''
+                    + ", timesAcquired=" + timesAcquired
+                    + ", totalTimeHeldMs=" + totalTimeHeldMs
+                    + ", timeHeldMs=" + timeHeldMs
+                    + '}';
+        }
+    }
+
+    private final List<WakeLock> mWakeLocks;
+
+    /** @hide **/
+    public WakeLockStats(@NonNull List<WakeLock> wakeLocks) {
+        mWakeLocks = wakeLocks;
+    }
+
+    @NonNull
+    public List<WakeLock> getWakeLocks() {
+        return mWakeLocks;
+    }
+
+    private WakeLockStats(Parcel in) {
+        final int size = in.readInt();
+        mWakeLocks = new ArrayList<>(size);
+        for (int i = 0; i < size; i++) {
+            mWakeLocks.add(new WakeLock(in));
+        }
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel out, int flags) {
+        final int size = mWakeLocks.size();
+        out.writeInt(size);
+        for (int i = 0; i < size; i++) {
+            WakeLock stats = mWakeLocks.get(i);
+            stats.writeToParcel(out);
+        }
+    }
+
+    @NonNull
+    public static final Creator<WakeLockStats> CREATOR =
+            new Creator<WakeLockStats>() {
+                public WakeLockStats createFromParcel(Parcel in) {
+                    return new WakeLockStats(in);
+                }
+
+                public WakeLockStats[] newArray(int size) {
+                    return new WakeLockStats[size];
+                }
+            };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public String toString() {
+        return "WakeLockStats " + mWakeLocks;
+    }
+}
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 5e4057b..29accb9 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -1525,10 +1525,11 @@
             result = totalBytes * CACHE_RESERVE_PERCENT_LOW / 100;
         } else {
             // Else, linearly interpolate the amount of space to reserve
-            result = ((CACHE_RESERVE_PERCENT_HIGH - CACHE_RESERVE_PERCENT_LOW)
-                      * (usableBytes - storageThresholdHighBytes) + CACHE_RESERVE_PERCENT_HIGH
-                      * (storageThresholdHighBytes - storageThresholdLowBytes)) * totalBytes
-                      / (100 * (storageThresholdHighBytes - storageThresholdLowBytes));
+            double slope = (CACHE_RESERVE_PERCENT_HIGH - CACHE_RESERVE_PERCENT_LOW) * totalBytes
+                    / (100.0 * (storageThresholdHighBytes - storageThresholdLowBytes));
+            double intercept = totalBytes * CACHE_RESERVE_PERCENT_LOW / 100.0
+                    - storageThresholdLowBytes * slope;
+            result = Math.round(slope * usableBytes + intercept);
         }
         return result;
     }
diff --git a/core/java/android/permission/IPermissionController.aidl b/core/java/android/permission/IPermissionController.aidl
index 66e1c5a..0e32a78 100644
--- a/core/java/android/permission/IPermissionController.aidl
+++ b/core/java/android/permission/IPermissionController.aidl
@@ -54,4 +54,6 @@
     void getGroupOfPlatformPermission(
             in String permissionName,
             in AndroidFuture<String> callback);
+    void getUnusedAppCount(
+            in AndroidFuture callback);
 }
diff --git a/core/java/android/permission/PermissionControllerManager.java b/core/java/android/permission/PermissionControllerManager.java
index 00f9e45..a0788e7 100644
--- a/core/java/android/permission/PermissionControllerManager.java
+++ b/core/java/android/permission/PermissionControllerManager.java
@@ -69,6 +69,7 @@
 import java.util.concurrent.Executor;
 import java.util.concurrent.TimeUnit;
 import java.util.function.Consumer;
+import java.util.function.IntConsumer;
 
 /**
  * Interface for communicating with the permission controller.
@@ -786,4 +787,34 @@
             }
         }, executor);
     }
+
+    /**
+     * Get the number of unused, hibernating apps for the user.
+     *
+     * @param executor executor to run callback on
+     * @param callback callback for when result is generated
+     */
+    public void getUnusedAppCount(@NonNull @CallbackExecutor Executor executor,
+            @NonNull IntConsumer callback) {
+        checkNotNull(executor);
+        checkNotNull(callback);
+
+        mRemoteService.postAsync(service -> {
+            AndroidFuture<Integer> unusedAppCountResult = new AndroidFuture<>();
+            service.getUnusedAppCount(unusedAppCountResult);
+            return unusedAppCountResult;
+        }).whenCompleteAsync((count, err) -> {
+            if (err != null) {
+                Log.e(TAG, "Error getting unused app count", err);
+                callback.accept(0);
+            } else {
+                final long token = Binder.clearCallingIdentity();
+                try {
+                    callback.accept((int) count);
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
+            }
+        });
+    }
 }
diff --git a/core/java/android/permission/PermissionControllerService.java b/core/java/android/permission/PermissionControllerService.java
index 8854e27..c979303 100644
--- a/core/java/android/permission/PermissionControllerService.java
+++ b/core/java/android/permission/PermissionControllerService.java
@@ -340,6 +340,20 @@
         throw new AbstractMethodError("Must be overridden in implementing class");
     }
 
+    /**
+     * Get the count of unused, hibernating apps on the device.
+     *
+     * @param callback callback after count is retrieved
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.MANAGE_APP_HIBERNATION)
+    @NonNull
+    public void onGetUnusedAppCount(@NonNull IntConsumer callback) {
+        throw new AbstractMethodError("Must be overridden in implementing class");
+    }
+
     @Override
     public final @NonNull IBinder onBind(Intent intent) {
         return new IPermissionController.Stub() {
@@ -618,6 +632,20 @@
                     callback.completeExceptionally(t);
                 }
             }
+
+            @Override
+            public void getUnusedAppCount(@NonNull AndroidFuture callback) {
+                try {
+                    Objects.requireNonNull(callback);
+
+                    enforceSomePermissionsGrantedToCaller(
+                            Manifest.permission.MANAGE_APP_HIBERNATION);
+
+                    PermissionControllerService.this.onGetUnusedAppCount(callback::complete);
+                } catch (Throwable t) {
+                    callback.completeExceptionally(t);
+                }
+            }
         };
     }
 }
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
index e2f5908..61e48c5 100644
--- a/core/java/android/permission/PermissionManager.java
+++ b/core/java/android/permission/PermissionManager.java
@@ -24,6 +24,8 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
@@ -101,6 +103,26 @@
      */
     public static final int PERMISSION_HARD_DENIED = 2;
 
+    /**
+     * Activity action: Launch UI to review permission decisions.
+     * <p>
+     * <strong>Important:</strong>You must protect the activity that handles this action with the
+     * {@link android.Manifest.permission#START_REVIEW_PERMISSION_DECISIONS} permission to ensure
+     * that only the system can launch this activity. The system will not launch activities that are
+     * not properly protected.
+     * <p>
+     * Input: Nothing.
+     * </p>
+     * <p>
+     * Output: Nothing.
+     * </p>
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    @RequiresPermission(android.Manifest.permission.START_REVIEW_PERMISSION_DECISIONS)
+    public static final String ACTION_REVIEW_PERMISSION_DECISIONS =
+            "android.permission.action.REVIEW_PERMISSION_DECISIONS";
+
+
     /** @hide */
     public static final String LOG_TAG_TRACE_GRANTS = "PermissionGrantTrace";
 
@@ -218,7 +240,8 @@
     /**
      * Checks whether a given data access chain described by the given {@link AttributionSource}
      * has a given permission. Call this method if you are the datasource which would not blame you
-     * for access to the data since you are the data.
+     * for access to the data since you are the data. Use this API if you are the datasource of the
+     * protected state.
      *
      * <strong>NOTE:</strong> Use this method only for permission checks at the
      * point where you will deliver the permission protected data to clients.
diff --git a/core/java/android/permission/PermissionUsageHelper.java b/core/java/android/permission/PermissionUsageHelper.java
index f0e6624..658e033 100644
--- a/core/java/android/permission/PermissionUsageHelper.java
+++ b/core/java/android/permission/PermissionUsageHelper.java
@@ -318,7 +318,7 @@
             String permGroup = usedPermGroups.get(permGroupNum);
 
             ArrayMap<OpUsage, CharSequence> usagesWithLabels =
-                    getUniqueUsagesWithLabels(rawUsages.get(permGroup));
+                    getUniqueUsagesWithLabels(permGroup, rawUsages.get(permGroup));
 
             if (permGroup.equals(OPSTR_PHONE_CALL_MICROPHONE)) {
                 isPhone = true;
@@ -439,7 +439,8 @@
         return ListFormatter.getInstance().format(labels);
     }
 
-    private ArrayMap<OpUsage, CharSequence> getUniqueUsagesWithLabels(List<OpUsage> usages) {
+    private ArrayMap<OpUsage, CharSequence> getUniqueUsagesWithLabels(String permGroup,
+            List<OpUsage> usages) {
         ArrayMap<OpUsage, CharSequence> usagesAndLabels = new ArrayMap<>();
 
         if (usages == null || usages.isEmpty()) {
@@ -474,7 +475,7 @@
             // If this usage has a proxy, but is not a proxy, it is the end of a chain.
             // TODO remove once camera converted
             if (!proxies.containsKey(usageAttr) && usage.proxy != null
-                    && !usage.op.equals(OPSTR_RECORD_AUDIO)) {
+                    && !MICROPHONE.equals(permGroup)) {
                 proxyLabels.put(usage, new ArrayList<>());
                 proxyPackages.add(usage.getPackageIdHash());
             }
@@ -546,7 +547,7 @@
 
             // TODO ntmyren: remove this proxy logic once camera is converted to AttributionSource
             // For now: don't add mic proxy usages
-            if (!start.op.equals(OPSTR_RECORD_AUDIO)) {
+            if (!MICROPHONE.equals(permGroup)) {
                 usagesAndLabels.put(start,
                         proxyLabelList.isEmpty() ? null : formatLabelList(proxyLabelList));
             }
@@ -560,7 +561,8 @@
                 // if the list is empty or incomplete, do not show it.
                 if (usageList.isEmpty() || !usageList.get(lastVisible).isEnd()
                         || !usageList.get(0).isStart()
-                        || !usageList.get(lastVisible).usage.op.equals(OPSTR_RECORD_AUDIO)) {
+                        || !permGroup.equals(getGroupForOp(usageList.get(0).usage.op))
+                        || !MICROPHONE.equals(permGroup)) {
                     continue;
                 }
 
diff --git a/core/java/android/provider/BlockedNumberContract.java b/core/java/android/provider/BlockedNumberContract.java
index dd2ea81..5d00b29 100644
--- a/core/java/android/provider/BlockedNumberContract.java
+++ b/core/java/android/provider/BlockedNumberContract.java
@@ -231,7 +231,7 @@
             prefix = { "STATUS_" },
             value = {STATUS_NOT_BLOCKED, STATUS_BLOCKED_IN_LIST, STATUS_BLOCKED_RESTRICTED,
                     STATUS_BLOCKED_UNKNOWN_NUMBER, STATUS_BLOCKED_PAYPHONE,
-                    STATUS_BLOCKED_NOT_IN_CONTACTS})
+                    STATUS_BLOCKED_NOT_IN_CONTACTS, STATUS_BLOCKED_UNAVAILABLE})
     public @interface BlockStatus {}
 
     /**
@@ -277,6 +277,13 @@
     public static final int STATUS_BLOCKED_NOT_IN_CONTACTS = 5;
 
     /**
+     * Integer reason code used with {@link #RES_BLOCK_STATUS} to indicate that a call was blocked
+     * because it is from a number not available.
+     * @hide
+     */
+    public static final int STATUS_BLOCKED_UNAVAILABLE = 6;
+
+    /**
      * Integer reason indicating whether a call was blocked, and if so why.
      * @hide
      */
@@ -441,6 +448,9 @@
         /* Preference key for whether should show an emergency call notification. */
         public static final String ENHANCED_SETTING_KEY_SHOW_EMERGENCY_CALL_NOTIFICATION =
                 "show_emergency_call_notification";
+        /* Preference key of block unavailable calls setting. */
+        public static final String ENHANCED_SETTING_KEY_BLOCK_UNAVAILABLE =
+                "block_unavailable_calls_setting";
 
         /**
          * Notifies the provider that emergency services were contacted by the user.
@@ -547,6 +557,7 @@
          *        {@link #ENHANCED_SETTING_KEY_BLOCK_PRIVATE}
          *        {@link #ENHANCED_SETTING_KEY_BLOCK_PAYPHONE}
          *        {@link #ENHANCED_SETTING_KEY_BLOCK_UNKNOWN}
+         *        {@link #ENHANCED_SETTING_KEY_BLOCK_UNAVAILABLE}
          *        {@link #ENHANCED_SETTING_KEY_EMERGENCY_CALL_NOTIFICATION_SHOWING}
          * @return {@code true} if the setting is enabled. {@code false} otherwise.
          */
@@ -574,6 +585,7 @@
          *        {@link #ENHANCED_SETTING_KEY_BLOCK_PRIVATE}
          *        {@link #ENHANCED_SETTING_KEY_BLOCK_PAYPHONE}
          *        {@link #ENHANCED_SETTING_KEY_BLOCK_UNKNOWN}
+         *        {@link #ENHANCED_SETTING_KEY_BLOCK_UNAVAILABLE}
          *        {@link #ENHANCED_SETTING_KEY_EMERGENCY_CALL_NOTIFICATION_SHOWING}
          * @param value the enabled statue of the setting to set.
          */
@@ -603,6 +615,8 @@
                     return "blocked - payphone";
                 case STATUS_BLOCKED_NOT_IN_CONTACTS:
                     return "blocked - not in contacts";
+                case STATUS_BLOCKED_UNAVAILABLE:
+                    return "blocked - unavailable";
             }
             return "unknown";
         }
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index 0cc5bfd..8dca7ab 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -910,6 +910,7 @@
          * <li>{@link #PRESENTATION_RESTRICTED}</li>
          * <li>{@link #PRESENTATION_UNKNOWN}</li>
          * <li>{@link #PRESENTATION_PAYPHONE}</li>
+         * <li>{@link #PRESENTATION_UNAVAILABLE}</li>
          * </ul>
          * </p>
          *
@@ -925,6 +926,8 @@
         public static final int PRESENTATION_UNKNOWN = 3;
         /** Number is a pay phone. */
         public static final int PRESENTATION_PAYPHONE = 4;
+        /** Number is unavailable. */
+        public static final int PRESENTATION_UNAVAILABLE = 5;
 
         /**
          * The ISO 3166-1 two letters country code of the country where the
@@ -2028,6 +2031,10 @@
                 return presentation;
             }
 
+            if (presentation == TelecomManager.PRESENTATION_UNAVAILABLE) {
+                return PRESENTATION_UNAVAILABLE;
+            }
+
             if (TextUtils.isEmpty(number)
                     || presentation == TelecomManager.PRESENTATION_UNKNOWN) {
                 return PRESENTATION_UNKNOWN;
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 22b9578..6349cde 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -564,6 +564,14 @@
     public static final String NAMESPACE_WINDOW_MANAGER_NATIVE_BOOT = "window_manager_native_boot";
 
     /**
+     * Definitions for selection toolbar related functions.
+     *
+     * @hide
+     */
+    @TestApi
+    public static final String NAMESPACE_SELECTION_TOOLBAR = "selection_toolbar";
+
+    /**
      * List of namespaces which can be read without READ_DEVICE_CONFIG permission
      *
      * @hide
@@ -571,7 +579,7 @@
     @NonNull
     private static final List<String> PUBLIC_NAMESPACES =
             Arrays.asList(NAMESPACE_TEXTCLASSIFIER, NAMESPACE_RUNTIME, NAMESPACE_STATSD_JAVA,
-                    NAMESPACE_STATSD_JAVA_BOOT);
+                    NAMESPACE_STATSD_JAVA_BOOT, NAMESPACE_SELECTION_TOOLBAR);
     /**
      * Privacy related properties definitions.
      *
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index edacffc..55ffdab 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -391,6 +391,21 @@
             "android.settings.REDUCE_BRIGHT_COLORS_SETTINGS";
 
     /**
+     * Activity Action: Show settings to allow configuration of Color correction.
+     * <p>
+     * In some cases, a matching Activity may not exist, so ensure you
+     * safeguard against this.
+     * <p>
+     * Input: Nothing.
+     * <p>
+     * Output: Nothing.
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_COLOR_CORRECTION_SETTINGS =
+            "com.android.settings.ACCESSIBILITY_COLOR_SPACE_SETTINGS";
+
+    /**
      * Activity Action: Show settings to allow configuration of Color inversion.
      * <p>
      * In some cases, a matching Activity may not exist, so ensure you
@@ -950,6 +965,19 @@
             "android.settings.LOCALE_SETTINGS";
 
     /**
+     * Activity Action: Show settings to allow configuration of per application locale.
+     * <p>
+     * Input: The Intent's data URI can specify the application package name to directly invoke the
+     * app locale details GUI specific to the package name.
+     * For example "package:com.my.app".
+     * <p>
+     * Output: Nothing.
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_APP_LOCALE_SETTINGS =
+            "android.settings.APP_LOCALE_SETTINGS";
+
+    /**
      * Activity Action: Show settings to allow configuration of lockscreen.
      * <p>
      * In some cases, a matching Activity may not exist, so ensure you
@@ -5945,7 +5973,6 @@
             MOVED_TO_GLOBAL.add(Settings.Global.CONNECTIVITY_CHANGE_DELAY);
             MOVED_TO_GLOBAL.add(Settings.Global.CAPTIVE_PORTAL_DETECTION_ENABLED);
             MOVED_TO_GLOBAL.add(Settings.Global.CAPTIVE_PORTAL_SERVER);
-            MOVED_TO_GLOBAL.add(Settings.Global.NSD_ON);
             MOVED_TO_GLOBAL.add(Settings.Global.SET_INSTALL_LOCATION);
             MOVED_TO_GLOBAL.add(Settings.Global.DEFAULT_INSTALL_LOCATION);
             MOVED_TO_GLOBAL.add(Settings.Global.INET_CONDITION_DEBOUNCE_UP_DELAY);
@@ -6496,6 +6523,27 @@
         public static final String ALLOW_MOCK_LOCATION = "mock_location";
 
         /**
+         * This is used by Bluetooth Manager to store adapter name
+         * @hide
+         */
+        @Readable(maxTargetSdk = Build.VERSION_CODES.S)
+        public static final String BLUETOOTH_NAME = "bluetooth_name";
+
+        /**
+         * This is used by Bluetooth Manager to store adapter address
+         * @hide
+         */
+        @Readable(maxTargetSdk = Build.VERSION_CODES.S)
+        public static final String BLUETOOTH_ADDRESS = "bluetooth_address";
+
+        /**
+         * This is used by Bluetooth Manager to store whether adapter address is valid
+         * @hide
+         */
+        @Readable(maxTargetSdk = Build.VERSION_CODES.S)
+        public static final String BLUETOOTH_ADDR_VALID = "bluetooth_addr_valid";
+
+        /**
          * Setting to indicate that on device captions are enabled.
          *
          * @hide
@@ -6504,6 +6552,16 @@
         @Readable
         public static final String ODI_CAPTIONS_ENABLED = "odi_captions_enabled";
 
+
+        /**
+         * Setting to indicate live caption button show or hide in the volume
+         * rocker.
+         *
+         * @hide
+         */
+        public static final String ODI_CAPTIONS_VOLUME_UI_ENABLED =
+                "odi_captions_volume_ui_enabled";
+
         /**
          * On Android 8.0 (API level 26) and higher versions of the platform,
          * a 64-bit number (expressed as a hexadecimal string), unique to
@@ -10061,6 +10119,14 @@
                 "theme_customization_overlay_packages";
 
         /**
+         * Indicates whether the device is in kids nav mode.
+         * <p>Type: int (0 for false, 1 for true)
+         *
+         * @hide
+         */
+        public static final String NAV_BAR_KIDS_MODE = "nav_bar_kids_mode";
+
+        /**
          * Navigation bar mode.
          *  0 = 3 button
          *  1 = 2 button
@@ -10424,13 +10490,6 @@
         public static final String COMMUNAL_MODE_ENABLED = "communal_mode_enabled";
 
         /**
-         * An array of all the packages which have been enabled for hub mode by the user.
-         *
-         * @hide
-         */
-        public static final String COMMUNAL_MODE_PACKAGES = "communal_mode_packages";
-
-        /**
          * An array of SSIDs of Wi-Fi networks that, when connected, are considered safe to enable
          * the communal mode.
          *
@@ -12857,13 +12916,6 @@
         @Readable
         public static final String MIN_DURATION_BETWEEN_RECOVERY_STEPS_IN_MS =
                 "min_duration_between_recovery_steps";
-        /**
-         * Whether network service discovery is enabled.
-         *
-         * @hide
-         */
-        @Readable
-        public static final String NSD_ON = "nsd_on";
 
         /**
          * Let user pick default install location.
@@ -15165,7 +15217,10 @@
          * {@code p1[url_bar]:p2:p3[url_foo,url_bas]}
          *
          * @hide
+         * @deprecated Use {@link android.view.autofill.AutofillManager
+         * #DEVICE_CONFIG_AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES} instead.
          */
+        @Deprecated
         @SystemApi
         @Readable
         public static final String AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES =
@@ -17045,6 +17100,15 @@
              */
             public static final String CLOCKWORK_SYSUI_MAIN_ACTIVITY =
                     "clockwork_sysui_main_activity";
+
+            /**
+             * Setting to disable power button long press launching Assistant. It's boolean, i.e.
+             * enabled = 1, disabled = 0. By default, this setting is enabled.
+             *
+             * @hide
+             */
+            public static final String CLOCKWORK_LONG_PRESS_TO_ASSISTANT_ENABLED =
+                    "clockwork_long_press_to_assistant_enabled";
         }
     }
 
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index e3c3969..34e35d4 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -3589,7 +3589,7 @@
          * @hide
          */
         public static final Uri PREFERRED_APN_URI = Uri.parse(
-                "content://telephony/carriers/preferapn/subId/");
+                "content://telephony/carriers/preferapn/subId");
 
         /**
          * The {@code content://} style URL for the perferred APN set id.
@@ -3597,8 +3597,15 @@
          * @hide
          */
         public static final Uri PREFERRED_APN_SET_URI = Uri.parse(
-                "content://telephony/carriers/preferapnset/subId/");
+                "content://telephony/carriers/preferapnset/subId");
 
+        /**
+         * The id of preferred APN.
+         *
+         * @see #PREFERRED_APN_URI
+         * @hide
+         */
+        public static final String APN_ID = "apn_id";
 
         /**
          * The column name for ENFORCE_MANAGED_URI, indicates whether DPC-owned APNs are enforced.
diff --git a/core/java/android/service/autofill/AutofillService.java b/core/java/android/service/autofill/AutofillService.java
index 13274c6..29c7796 100644
--- a/core/java/android/service/autofill/AutofillService.java
+++ b/core/java/android/service/autofill/AutofillService.java
@@ -465,7 +465,7 @@
  * <p>Prior to Android {@link android.os.Build.VERSION_CODES#P}, the metrics covered just the
  * scenarios where the service knew how to autofill an activity, but Android
  * {@link android.os.Build.VERSION_CODES#P} introduced a new mechanism called field classification,
- * which allows the service to dinamically classify the meaning of fields based on the existing user
+ * which allows the service to dynamically classify the meaning of fields based on the existing user
  * data known by the service.
  *
  * <p>Typically, field classification can be used to detect fields that can be autofilled with
diff --git a/telephony/java/com/android/internal/telephony/euicc/IResultCallback.aidl b/core/java/android/service/games/CreateGameSessionRequest.aidl
similarity index 76%
copy from telephony/java/com/android/internal/telephony/euicc/IResultCallback.aidl
copy to core/java/android/service/games/CreateGameSessionRequest.aidl
index 69f479c..e09cc8e 100644
--- a/telephony/java/com/android/internal/telephony/euicc/IResultCallback.aidl
+++ b/core/java/android/service/games/CreateGameSessionRequest.aidl
@@ -13,11 +13,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.internal.telephony.euicc;
 
-import android.content.Intent;
+package android.service.games;
 
-/** @hide */
-oneway interface IResultCallback {
-    void onComplete(int resultCode, in Intent resultIntent);
-}
+
+/**
+ * @hide
+ */
+parcelable CreateGameSessionRequest;
\ No newline at end of file
diff --git a/core/java/android/service/games/CreateGameSessionRequest.java b/core/java/android/service/games/CreateGameSessionRequest.java
new file mode 100644
index 0000000..2129cb1
--- /dev/null
+++ b/core/java/android/service/games/CreateGameSessionRequest.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 android.service.games;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * Request object providing the context in order to create a new {@link GameSession}.
+ *
+ * This is provided to the Game Service provider via
+ * {@link GameSessionService#onNewSession(CreateGameSessionRequest)}. It includes game
+ * (see {@link #getGamePackageName()}) that the session is associated with and a task
+ * (see {@link #getTaskId()}.
+ *
+ * @hide
+ */
+@SystemApi
+public final class CreateGameSessionRequest implements Parcelable {
+
+    @NonNull
+    public static final Parcelable.Creator<CreateGameSessionRequest> CREATOR =
+            new Parcelable.Creator<CreateGameSessionRequest>() {
+                @Override
+                public CreateGameSessionRequest createFromParcel(Parcel source) {
+                    return new CreateGameSessionRequest(
+                            source.readInt(),
+                            source.readString8());
+                }
+
+                @Override
+                public CreateGameSessionRequest[] newArray(int size) {
+                    return new CreateGameSessionRequest[0];
+                }
+            };
+
+    private final int mTaskId;
+    private final String mGamePackageName;
+
+    public CreateGameSessionRequest(int taskId, @NonNull String gamePackageName) {
+        this.mTaskId = taskId;
+        this.mGamePackageName = gamePackageName;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeInt(mTaskId);
+        dest.writeString8(mGamePackageName);
+    }
+
+    /**
+     * Unique identifier for the task.
+     */
+    public int getTaskId() {
+        return mTaskId;
+    }
+
+    /**
+     * The package name of the game associated with the session.
+     */
+    @NonNull
+    public String getGamePackageName() {
+        return mGamePackageName;
+    }
+
+    @Override
+    public String toString() {
+        return "GameSessionRequest{"
+                + "mTaskId="
+                + mTaskId
+                + ", mGamePackageName='"
+                + mGamePackageName
+                + "\'}";
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+
+        if (!(o instanceof CreateGameSessionRequest)) {
+            return false;
+        }
+
+        CreateGameSessionRequest that = (CreateGameSessionRequest) o;
+        return mTaskId == that.mTaskId
+                && Objects.equals(mGamePackageName, that.mGamePackageName);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mTaskId, mGamePackageName);
+    }
+}
diff --git a/core/java/android/service/games/GameService.java b/core/java/android/service/games/GameService.java
index 4b440dd..b79c055 100644
--- a/core/java/android/service/games/GameService.java
+++ b/core/java/android/service/games/GameService.java
@@ -46,7 +46,7 @@
  */
 @SystemApi
 public class GameService extends Service {
-    static final String TAG = "GameService";
+    private static final String TAG = "GameService";
 
     /**
      * The {@link Intent} that must be declared as handled by the service.
@@ -55,8 +55,16 @@
      * that other applications can not abuse it.
      */
     @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
-    public static final String SERVICE_INTERFACE =
-            "android.service.games.GameService";
+    public static final String ACTION_GAME_SERVICE =
+            "android.service.games.action.GAME_SERVICE";
+
+    /**
+     * Name under which a GameService component publishes information about itself.
+     * This meta-data should reference an XML resource containing a
+     * <code>&lt;{@link
+     * android.R.styleable#GameService game-session-service}&gt;</code> tag.
+     */
+    public static final String SERVICE_META_DATA = "android.game_service";
 
     private IGameManagerService mGameManagerService;
     private final IGameService mInterface = new IGameService.Stub() {
@@ -72,6 +80,7 @@
                     GameService::onDisconnected, GameService.this));
         }
     };
+
     private final IBinder.DeathRecipient mGameManagerServiceDeathRecipient = () -> {
         Log.w(TAG, "System service binder died. Shutting down");
 
@@ -82,9 +91,10 @@
     @Override
     @Nullable
     public IBinder onBind(@Nullable Intent intent) {
-        if (SERVICE_INTERFACE.equals(intent.getAction())) {
+        if (ACTION_GAME_SERVICE.equals(intent.getAction())) {
             return mInterface.asBinder();
         }
+
         return null;
     }
 
diff --git a/core/java/android/service/games/GameSession.java b/core/java/android/service/games/GameSession.java
new file mode 100644
index 0000000..0ff08c0
--- /dev/null
+++ b/core/java/android/service/games/GameSession.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.service.games;
+
+import android.annotation.SystemApi;
+import android.os.Handler;
+
+import com.android.internal.util.function.pooled.PooledLambda;
+
+/**
+ * An active game session, providing a facility for the implementation to interact with the game.
+ *
+ * A Game Service provider should extend the {@link GameSession} to provide their own implementation
+ * which is then returned when a game session is created via
+ * {@link GameSessionService#onNewSession(CreateGameSessionRequest)}.
+ *
+ * @hide
+ */
+@SystemApi
+public abstract class GameSession {
+
+    final IGameSession mInterface = new IGameSession.Stub() {
+        @Override
+        public void destroy() {
+            Handler.getMain().executeOrSendMessage(PooledLambda.obtainMessage(
+                    GameSession::doDestroy, GameSession.this));
+        }
+    };
+
+    void doCreate() {
+        onCreate();
+    }
+
+    void doDestroy() {
+        onDestroy();
+    }
+
+    /**
+     * Initializer called when the game session is starting.
+     *
+     * This should be used perform any setup required now that the game session is created.
+     */
+    public void onCreate() {}
+
+    /**
+     * Finalizer called when the game session is ending.
+     *
+     * This should be used to perform any cleanup before the game session is destroyed.
+     */
+    public void onDestroy() {}
+}
diff --git a/core/java/android/service/games/GameSessionService.java b/core/java/android/service/games/GameSessionService.java
new file mode 100644
index 0000000..a2c8870
--- /dev/null
+++ b/core/java/android/service/games/GameSessionService.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.service.games;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SdkConstant;
+import android.annotation.SystemApi;
+import android.app.Service;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.IBinder;
+
+import com.android.internal.infra.AndroidFuture;
+import com.android.internal.util.function.pooled.PooledLambda;
+
+import java.util.Objects;
+
+/**
+ * Service that hosts active game sessions.
+ *
+ * This service should be in a separate process from the {@link GameService}. This
+ * allows it to perform the heavyweight operations associated with rendering a game
+ * session overlay while games are running and release these resources (by allowing
+ * the process to be killed) when games are not running.
+ *
+ * Game Service providers must extend {@link GameSessionService} and declare the service in their
+ * Manifest. The service must require the {@link android.Manifest.permission#BIND_GAME_SERVICE} so
+ * that other application can not abuse it. This service is used to create instances of
+ * {@link GameSession} via {@link #onNewSession(CreateGameSessionRequest)} and will remain bound to
+ * so long as at least one {@link GameSession} is running.
+ *
+ * @hide
+ */
+@SystemApi
+public abstract class GameSessionService extends Service {
+    private static final String TAG = "GameSessionService";
+
+    /**
+     * The {@link Intent} action used when binding to the service.
+     * To be supported, the service must require the
+     * {@link android.Manifest.permission#BIND_GAME_SERVICE} permission so
+     * that other applications can not abuse it.
+     */
+    @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
+    public static final String ACTION_GAME_SESSION_SERVICE =
+            "android.service.games.action.GAME_SESSION_SERVICE";
+
+    private final IGameSessionService mInterface = new IGameSessionService.Stub() {
+        @Override
+        public void create(CreateGameSessionRequest createGameSessionRequest,
+                AndroidFuture gameSessionFuture) {
+            Handler.getMain().post(PooledLambda.obtainRunnable(
+                    GameSessionService::doCreate, GameSessionService.this,
+                    createGameSessionRequest,
+                    gameSessionFuture));
+        }
+    };
+
+    @Override
+    @Nullable
+    public IBinder onBind(@Nullable Intent intent) {
+        if (intent == null) {
+            return null;
+        }
+
+        if (!ACTION_GAME_SESSION_SERVICE.equals(intent.getAction())) {
+            return null;
+        }
+
+        return mInterface.asBinder();
+    }
+
+    private void doCreate(CreateGameSessionRequest createGameSessionRequest,
+            AndroidFuture<IBinder> gameSessionFuture) {
+        GameSession gameSession = onNewSession(createGameSessionRequest);
+        Objects.requireNonNull(gameSession);
+
+        gameSessionFuture.complete(gameSession.mInterface.asBinder());
+
+        gameSession.doCreate();
+    }
+
+    /**
+     * Request to create a new {@link GameSession}.
+     */
+    @NonNull
+    public abstract GameSession onNewSession(
+            @NonNull CreateGameSessionRequest createGameSessionRequest);
+}
diff --git a/telephony/java/com/android/internal/telephony/euicc/IResultCallback.aidl b/core/java/android/service/games/IGameSession.aidl
similarity index 76%
copy from telephony/java/com/android/internal/telephony/euicc/IResultCallback.aidl
copy to core/java/android/service/games/IGameSession.aidl
index 69f479c..b2e9f1d 100644
--- a/telephony/java/com/android/internal/telephony/euicc/IResultCallback.aidl
+++ b/core/java/android/service/games/IGameSession.aidl
@@ -13,11 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.internal.telephony.euicc;
 
-import android.content.Intent;
+package android.service.games;
 
-/** @hide */
-oneway interface IResultCallback {
-    void onComplete(int resultCode, in Intent resultIntent);
+/**
+ * @hide
+ */
+oneway interface IGameSession {
+    void destroy();
 }
diff --git a/telephony/java/com/android/internal/telephony/euicc/IResultCallback.aidl b/core/java/android/service/games/IGameSessionService.aidl
similarity index 60%
copy from telephony/java/com/android/internal/telephony/euicc/IResultCallback.aidl
copy to core/java/android/service/games/IGameSessionService.aidl
index 69f479c..2a53ea7 100644
--- a/telephony/java/com/android/internal/telephony/euicc/IResultCallback.aidl
+++ b/core/java/android/service/games/IGameSessionService.aidl
@@ -13,11 +13,20 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.internal.telephony.euicc;
 
-import android.content.Intent;
+package android.service.games;
 
-/** @hide */
-oneway interface IResultCallback {
-    void onComplete(int resultCode, in Intent resultIntent);
+import android.service.games.IGameSession;
+import android.service.games.CreateGameSessionRequest;
+
+import com.android.internal.infra.AndroidFuture;
+
+
+/**
+ * @hide
+ */
+oneway interface IGameSessionService {
+    void create(
+            in CreateGameSessionRequest createGameSessionRequest,
+            in AndroidFuture /* T=IBinder for IGameSession */ gameSessionFuture);
 }
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index e64d685..4bbfbc2 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -38,7 +38,6 @@
 import android.graphics.Bitmap;
 import android.graphics.Rect;
 import android.graphics.Region;
-import android.inputmethodservice.SoftInputWindow;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.CancellationSignal;
@@ -157,7 +156,7 @@
     TypedArray mThemeAttrs;
     View mRootView;
     FrameLayout mContentFrame;
-    SoftInputWindow mWindow;
+    VoiceInteractionWindow mWindow;
 
     boolean mUiEnabled = true;
     boolean mInitialized;
@@ -859,7 +858,7 @@
     static final int MSG_REGISTER_VISIBLE_ACTIVITY_CALLBACK = 110;
     static final int MSG_UNREGISTER_VISIBLE_ACTIVITY_CALLBACK = 111;
 
-    class MyCallbacks implements HandlerCaller.Callback, SoftInputWindow.Callback {
+    class MyCallbacks implements HandlerCaller.Callback, VoiceInteractionWindow.Callback {
         @Override
         public void executeMessage(Message msg) {
             SomeArgs args = null;
@@ -1250,7 +1249,7 @@
         mInitialized = true;
         mInflater = (LayoutInflater)mContext.getSystemService(
                 Context.LAYOUT_INFLATER_SERVICE);
-        mWindow = new SoftInputWindow(mContext, "VoiceInteractionSession", mTheme,
+        mWindow = new VoiceInteractionWindow(mContext, "VoiceInteractionSession", mTheme,
                 mCallbacks, this, mDispatcherState,
                 WindowManager.LayoutParams.TYPE_VOICE_INTERACTION, Gravity.BOTTOM, true);
         mWindow.getWindow().getAttributes().setFitInsetsTypes(0 /* types */);
diff --git a/core/java/android/service/voice/VoiceInteractionWindow.java b/core/java/android/service/voice/VoiceInteractionWindow.java
new file mode 100644
index 0000000..ba1fd45
--- /dev/null
+++ b/core/java/android/service/voice/VoiceInteractionWindow.java
@@ -0,0 +1,320 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.service.voice;
+
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.annotation.IntDef;
+import android.app.Dialog;
+import android.content.Context;
+import android.graphics.Rect;
+import android.os.Debug;
+import android.os.IBinder;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.WindowManager;
+
+import java.lang.annotation.Retention;
+
+/**
+ * A {@link VoiceInteractionWindow} is a {@link Dialog} that is intended to be used for a top-level
+ * {@link VoiceInteractionSession}. It will be displayed along the edge of the screen, moving the
+ * application user interface away from it so that the focused item is always visible.
+ */
+final class VoiceInteractionWindow extends Dialog {
+    private static final boolean DEBUG = false;
+    private static final String TAG = "VoiceInteractionWindow";
+
+    private final String mName;
+    private final Callback mCallback;
+    private final KeyEvent.Callback mKeyEventCallback;
+    private final KeyEvent.DispatcherState mDispatcherState;
+    private final int mWindowType;
+    private final int mGravity;
+    private final boolean mTakesFocus;
+    private final Rect mBounds = new Rect();
+
+    @Retention(SOURCE)
+    @IntDef(value = {WindowState.TOKEN_PENDING, WindowState.TOKEN_SET,
+            WindowState.SHOWN_AT_LEAST_ONCE, WindowState.REJECTED_AT_LEAST_ONCE,
+            WindowState.DESTROYED})
+    private @interface WindowState {
+        /**
+         * The window token is not set yet.
+         */
+        int TOKEN_PENDING = 0;
+        /**
+         * The window token was set, but the window is not shown yet.
+         */
+        int TOKEN_SET = 1;
+        /**
+         * The window was shown at least once.
+         */
+        int SHOWN_AT_LEAST_ONCE = 2;
+        /**
+         * {@link WindowManager.BadTokenException} was sent when calling
+         * {@link Dialog#show()} at least once.
+         */
+        int REJECTED_AT_LEAST_ONCE = 3;
+        /**
+         * The window is considered destroyed.  Any incoming request should be ignored.
+         */
+        int DESTROYED = 4;
+    }
+
+    @WindowState
+    private int mWindowState = WindowState.TOKEN_PENDING;
+
+    /**
+     * Used to provide callbacks.
+     */
+    interface Callback {
+        /**
+         * Used to be notified when {@link Dialog#onBackPressed()} gets called.
+         */
+        void onBackPressed();
+    }
+
+    /**
+     * Set {@link IBinder} window token to the window.
+     *
+     * <p>This method can be called only once.</p>
+     * @param token {@link IBinder} token to be associated with the window.
+     */
+    void setToken(IBinder token) {
+        switch (mWindowState) {
+            case WindowState.TOKEN_PENDING:
+                // Normal scenario.  Nothing to worry about.
+                WindowManager.LayoutParams lp = getWindow().getAttributes();
+                lp.token = token;
+                getWindow().setAttributes(lp);
+                updateWindowState(WindowState.TOKEN_SET);
+
+                // As soon as we have a token, make sure the window is added (but not shown) by
+                // setting visibility to INVISIBLE and calling show() on Dialog. Note that
+                // WindowInsetsController.OnControllableInsetsChangedListener relies on the window
+                // being added to function.
+                getWindow().getDecorView().setVisibility(View.INVISIBLE);
+                show();
+                return;
+            case WindowState.TOKEN_SET:
+            case WindowState.SHOWN_AT_LEAST_ONCE:
+            case WindowState.REJECTED_AT_LEAST_ONCE:
+                throw new IllegalStateException("setToken can be called only once");
+            case WindowState.DESTROYED:
+                // Just ignore.  Since there are multiple event queues from the token is issued
+                // in the system server to the timing when it arrives here, it can be delivered
+                // after the is already destroyed.  No one should be blamed because of such an
+                // unfortunate but possible scenario.
+                Log.i(TAG, "Ignoring setToken() because window is already destroyed.");
+                return;
+            default:
+                throw new IllegalStateException("Unexpected state=" + mWindowState);
+        }
+    }
+
+    /**
+     * Create a {@link VoiceInteractionWindow} that uses a custom style.
+     *
+     * @param context The Context in which the DockWindow should run. In
+     *        particular, it uses the window manager and theme from this context
+     *        to present its UI.
+     * @param theme A style resource describing the theme to use for the window.
+     *        See <a href="{@docRoot}reference/available-resources.html#stylesandthemes">Style
+     *        and Theme Resources</a> for more information about defining and
+     *        using styles. This theme is applied on top of the current theme in
+     *        <var>context</var>. If 0, the default dialog theme will be used.
+     */
+    VoiceInteractionWindow(Context context, String name, int theme, Callback callback,
+            KeyEvent.Callback keyEventCallback, KeyEvent.DispatcherState dispatcherState,
+            int windowType, int gravity, boolean takesFocus) {
+        super(context, theme);
+        mName = name;
+        mCallback = callback;
+        mKeyEventCallback = keyEventCallback;
+        mDispatcherState = dispatcherState;
+        mWindowType = windowType;
+        mGravity = gravity;
+        mTakesFocus = takesFocus;
+        initDockWindow();
+    }
+
+    @Override
+    public void onWindowFocusChanged(boolean hasFocus) {
+        super.onWindowFocusChanged(hasFocus);
+        mDispatcherState.reset();
+    }
+
+    @Override
+    public boolean dispatchTouchEvent(MotionEvent ev) {
+        getWindow().getDecorView().getHitRect(mBounds);
+
+        if (ev.isWithinBoundsNoHistory(mBounds.left, mBounds.top,
+                mBounds.right - 1, mBounds.bottom - 1)) {
+            return super.dispatchTouchEvent(ev);
+        } else {
+            MotionEvent temp = ev.clampNoHistory(mBounds.left, mBounds.top,
+                    mBounds.right - 1, mBounds.bottom - 1);
+            boolean handled = super.dispatchTouchEvent(temp);
+            temp.recycle();
+            return handled;
+        }
+    }
+
+    private void updateWidthHeight(WindowManager.LayoutParams lp) {
+        if (lp.gravity == Gravity.TOP || lp.gravity == Gravity.BOTTOM) {
+            lp.width = WindowManager.LayoutParams.MATCH_PARENT;
+            lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
+        } else {
+            lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
+            lp.height = WindowManager.LayoutParams.MATCH_PARENT;
+        }
+    }
+
+    @Override
+    public boolean onKeyDown(int keyCode, KeyEvent event) {
+        if (mKeyEventCallback != null && mKeyEventCallback.onKeyDown(keyCode, event)) {
+            return true;
+        }
+        return super.onKeyDown(keyCode, event);
+    }
+
+    @Override
+    public boolean onKeyLongPress(int keyCode, KeyEvent event) {
+        if (mKeyEventCallback != null && mKeyEventCallback.onKeyLongPress(keyCode, event)) {
+            return true;
+        }
+        return super.onKeyLongPress(keyCode, event);
+    }
+
+    @Override
+    public boolean onKeyUp(int keyCode, KeyEvent event) {
+        if (mKeyEventCallback != null && mKeyEventCallback.onKeyUp(keyCode, event)) {
+            return true;
+        }
+        return super.onKeyUp(keyCode, event);
+    }
+
+    @Override
+    public boolean onKeyMultiple(int keyCode, int count, KeyEvent event) {
+        if (mKeyEventCallback != null && mKeyEventCallback.onKeyMultiple(keyCode, count, event)) {
+            return true;
+        }
+        return super.onKeyMultiple(keyCode, count, event);
+    }
+
+    @Override
+    public void onBackPressed() {
+        if (mCallback != null) {
+            mCallback.onBackPressed();
+        } else {
+            super.onBackPressed();
+        }
+    }
+
+    private void initDockWindow() {
+        WindowManager.LayoutParams lp = getWindow().getAttributes();
+
+        lp.type = mWindowType;
+        lp.setTitle(mName);
+
+        lp.gravity = mGravity;
+        updateWidthHeight(lp);
+
+        getWindow().setAttributes(lp);
+
+        int windowSetFlags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
+        int windowModFlags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+                | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+                | WindowManager.LayoutParams.FLAG_DIM_BEHIND;
+
+        if (!mTakesFocus) {
+            windowSetFlags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+        } else {
+            windowSetFlags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
+            windowModFlags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
+        }
+
+        getWindow().setFlags(windowSetFlags, windowModFlags);
+    }
+
+    @Override
+    public void show() {
+        switch (mWindowState) {
+            case WindowState.TOKEN_PENDING:
+                throw new IllegalStateException("Window token is not set yet.");
+            case WindowState.TOKEN_SET:
+            case WindowState.SHOWN_AT_LEAST_ONCE:
+                // Normal scenario.  Nothing to worry about.
+                try {
+                    super.show();
+                    updateWindowState(WindowState.SHOWN_AT_LEAST_ONCE);
+                } catch (WindowManager.BadTokenException e) {
+                    // Just ignore this exception.  Since show() can be requested from other
+                    // components such as the system and there could be multiple event queues before
+                    // the request finally arrives here, the system may have already invalidated the
+                    // window token attached to our window.  In such a scenario, receiving
+                    // BadTokenException here is an expected behavior.  We just ignore it and update
+                    // the state so that we do not touch this window later.
+                    Log.i(TAG, "Probably the IME window token is already invalidated."
+                            + " show() does nothing.");
+                    updateWindowState(WindowState.REJECTED_AT_LEAST_ONCE);
+                }
+                return;
+            case WindowState.REJECTED_AT_LEAST_ONCE:
+                // Just ignore.  In general we cannot completely avoid this kind of race condition.
+                Log.i(TAG, "Not trying to call show() because it was already rejected once.");
+                return;
+            case WindowState.DESTROYED:
+                // Just ignore.  In general we cannot completely avoid this kind of race condition.
+                Log.i(TAG, "Ignoring show() because the window is already destroyed.");
+                return;
+            default:
+                throw new IllegalStateException("Unexpected state=" + mWindowState);
+        }
+    }
+
+    private void updateWindowState(@WindowState int newState) {
+        if (DEBUG) {
+            if (mWindowState != newState) {
+                Log.d(TAG, "WindowState: " + stateToString(mWindowState) + " -> "
+                        + stateToString(newState) + " @ " + Debug.getCaller());
+            }
+        }
+        mWindowState = newState;
+    }
+
+    private static String stateToString(@WindowState int state) {
+        switch (state) {
+            case WindowState.TOKEN_PENDING:
+                return "TOKEN_PENDING";
+            case WindowState.TOKEN_SET:
+                return "TOKEN_SET";
+            case WindowState.SHOWN_AT_LEAST_ONCE:
+                return "SHOWN_AT_LEAST_ONCE";
+            case WindowState.REJECTED_AT_LEAST_ONCE:
+                return "REJECTED_AT_LEAST_ONCE";
+            case WindowState.DESTROYED:
+                return "DESTROYED";
+            default:
+                throw new IllegalStateException("Unknown state=" + state);
+        }
+    }
+}
diff --git a/core/java/android/telephony/PhoneStateListener.java b/core/java/android/telephony/PhoneStateListener.java
index 5b9d69c..e5c9adb 100644
--- a/core/java/android/telephony/PhoneStateListener.java
+++ b/core/java/android/telephony/PhoneStateListener.java
@@ -743,6 +743,7 @@
      * @see TelephonyManager#DATA_CONNECTING
      * @see TelephonyManager#DATA_CONNECTED
      * @see TelephonyManager#DATA_SUSPENDED
+     * @see TelephonyManager#DATA_HANDOVER_IN_PROGRESS
      * @deprecated Use {@link TelephonyCallback.DataConnectionStateListener} instead.
      */
     @Deprecated
diff --git a/core/java/android/telephony/TelephonyCallback.java b/core/java/android/telephony/TelephonyCallback.java
index 3028a6d..e8960b8 100644
--- a/core/java/android/telephony/TelephonyCallback.java
+++ b/core/java/android/telephony/TelephonyCallback.java
@@ -792,6 +792,7 @@
          * @see TelephonyManager#DATA_CONNECTING
          * @see TelephonyManager#DATA_CONNECTED
          * @see TelephonyManager#DATA_SUSPENDED
+         * @see TelephonyManager#DATA_HANDOVER_IN_PROGRESS
          */
         void onDataConnectionStateChanged(@TelephonyManager.DataState int state,
                 @Annotation.NetworkType int networkType);
@@ -1408,10 +1409,11 @@
          *
          * @param enabled {@code true} if data is enabled, otherwise disabled.
          * @param reason  Reason for data enabled/disabled.
-         *                See {@link TelephonyManager.DataEnabledReason}.
+         *                See {@link TelephonyManager.DataEnabledChangedReason}.
          */
         @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
-        void onDataEnabledChanged(boolean enabled, @TelephonyManager.DataEnabledReason int reason);
+        void onDataEnabledChanged(boolean enabled,
+                @TelephonyManager.DataEnabledChangedReason int reason);
     }
 
     /**
diff --git a/core/java/android/text/InputType.java b/core/java/android/text/InputType.java
index dfe4119..4ebecb7 100644
--- a/core/java/android/text/InputType.java
+++ b/core/java/android/text/InputType.java
@@ -18,7 +18,7 @@
 
 import android.view.inputmethod.InputConnection;
 import android.view.inputmethod.TextAttribute;
-import android.view.inputmethod.TextAttribute.TextAttributeBuilder;
+import android.view.inputmethod.TextAttribute.Builder;
 
 import java.util.List;
 
@@ -200,7 +200,7 @@
      * which has pronunciation characters and target characters. When the user is typing the
      * pronunciation charactes, the IME could provide the possible target characters to the user.
      * When this flag is set, the IME should insert the text conversion suggestions through
-     * {@link TextAttributeBuilder#setTextConversionSuggestions(List)} and
+     * {@link Builder#setTextConversionSuggestions(List)} and
      * the {@link TextAttribute} with initialized with the text conversion suggestions is provided
      * by the IME to the application. To receive the additional information, the application needs
      * to implement {@link InputConnection#setComposingText(CharSequence, int, TextAttribute)},
diff --git a/core/java/android/util/MemoryIntArray.java b/core/java/android/util/MemoryIntArray.java
index 6da38c2..5cbbbef 100644
--- a/core/java/android/util/MemoryIntArray.java
+++ b/core/java/android/util/MemoryIntArray.java
@@ -75,7 +75,7 @@
         final String name = UUID.randomUUID().toString();
         mFd = nativeCreate(name, size);
         mMemoryAddr = nativeOpen(mFd, mIsOwner);
-        mCloseGuard.open("close");
+        mCloseGuard.open("MemoryIntArray.close");
     }
 
     private MemoryIntArray(Parcel parcel) throws IOException {
@@ -86,7 +86,7 @@
         }
         mFd = pfd.detachFd();
         mMemoryAddr = nativeOpen(mFd, mIsOwner);
-        mCloseGuard.open("close");
+        mCloseGuard.open("MemoryIntArray.close");
     }
 
     /**
diff --git a/core/java/android/view/DisplayCutout.java b/core/java/android/view/DisplayCutout.java
index c1a5636..ae323226 100644
--- a/core/java/android/view/DisplayCutout.java
+++ b/core/java/android/view/DisplayCutout.java
@@ -585,8 +585,10 @@
      * Returns a list of {@code Rect}s, each of which is the bounding rectangle for a non-functional
      * area on the display.
      *
-     * There will be at most one non-functional area per short edge of the device, and none on
-     * the long edges.
+     * There will be at most one non-functional area per edge of the device.
+     *
+     * <p>Note that there is no bounding rectangle for waterfall cutout since it just represents the
+     * curved areas of the display but not the non-functional areas.</p>
      *
      * @return a list of bounding {@code Rect}s, one for each display cutout area. No empty Rect is
      * returned.
@@ -607,8 +609,10 @@
      * functional area on the display. Ordinal value of BoundPosition is used as an index of
      * the array.
      *
-     * There will be at most one non-functional area per short edge of the device, and none on
-     * the long edges.
+     * There will be at most one non-functional area per edge of the device.
+     *
+     * <p>Note that there is no bounding rectangle for waterfall cutout since it just represents the
+     * curved areas of the display but not the non-functional areas.</p>
      *
      * @return an array of bounding {@code Rect}s, one for each display cutout area. This might
      * contain ZERO_RECT, which means there is no cutout area at the position.
diff --git a/core/java/android/view/HandwritingInitiator.java b/core/java/android/view/HandwritingInitiator.java
new file mode 100644
index 0000000..8524ac84
--- /dev/null
+++ b/core/java/android/view/HandwritingInitiator.java
@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.graphics.Rect;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodManager;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * Initiates handwriting mode once it detects stylus movement in handwritable areas.
+ *
+ * It is designed to be used by  {@link ViewRootImpl}. For every stylus related MotionEvent that is
+ * dispatched to view tree, ViewRootImpl should call {@link #onTouchEvent} method of this class.
+ * And it will automatically request to enter the handwriting mode when the conditions meet.
+ *
+ * Notice that ViewRootImpl should still dispatch MotionEvents to view tree as usual.
+ * And if it successfully enters the handwriting mode, the ongoing MotionEvent stream will be
+ * routed to the input method. Input system will fabricate an ACTION_CANCEL and send to
+ * ViewRootImpl.
+ *
+ * This class does nothing if:
+ * a) MotionEvents are not from stylus.
+ * b) The user taps or long-clicks with a stylus etc.
+ * c) Stylus pointer down position is not within a handwritable area.
+ *
+ * Used by InputMethodManager.
+ * @hide
+ */
+public class HandwritingInitiator {
+    /**
+     * The touchSlop from {@link ViewConfiguration} used to decide whether a pointer is considered
+     * moving or stationary.
+     */
+    private final int mTouchSlop;
+    /**
+     * The timeout used to distinguish tap from handwriting. If the stylus doesn't move before this
+     * timeout, it's not considered as handwriting.
+     */
+    private final long mTapTimeoutInMillis;
+
+    private State mState = new State();
+
+    /**
+     * Helper method to reset the internal state of this class.
+     * Calling this method will also prevent the following MotionEvents
+     * triggers handwriting until the next stylus ACTION_DOWN/ACTION_POINTER_DOWN
+     * arrives.
+     */
+    private void reset() {
+        mState = new State();
+    }
+
+    /** The reference to the View that currently has the input connection. */
+    @Nullable
+    @VisibleForTesting
+    public WeakReference<View> mConnectedView = null;
+
+    /** The editor bound reported by the connected View. */
+    @Nullable
+    @VisibleForTesting
+    public Rect mEditorBound = null;
+
+    /**
+     * When InputConnection restarts for a View, View#onInputConnectionCreatedInternal
+     * might be called before View#onInputConnectionClosedInternal, so we need to count the input
+     * connections and only set mConnectedView to null when mConnectionCount is zero.
+     */
+    private int mConnectionCount = 0;
+    private final InputMethodManager mImm;
+
+    @VisibleForTesting
+    public HandwritingInitiator(ViewConfiguration viewConfiguration,
+            InputMethodManager inputMethodManager) {
+        mTouchSlop = viewConfiguration.getScaledTouchSlop();
+        mTapTimeoutInMillis = ViewConfiguration.getTapTimeout();
+        mImm = inputMethodManager;
+    }
+
+    /**
+     * Notify the HandwritingInitiator that a new MotionEvent has arrived.
+     * This method is non-block, and the event passed to this method should be dispatched to the
+     * View tree as usual. If HandwritingInitiator triggers the handwriting mode, an fabricated
+     * ACTION_CANCEL event will be sent to the ViewRootImpl.
+     * @param motionEvent the stylus MotionEvent.
+     */
+    @VisibleForTesting
+    public void onTouchEvent(MotionEvent motionEvent) {
+        final int maskedAction = motionEvent.getActionMasked();
+        switch (maskedAction) {
+            case MotionEvent.ACTION_DOWN:
+            case MotionEvent.ACTION_POINTER_DOWN:
+                final int actionIndex = motionEvent.getActionIndex();
+                final int toolType = motionEvent.getToolType(actionIndex);
+                // TOOL_TYPE_ERASER is also from stylus. This indicates that the user is holding
+                // the eraser button during handwriting.
+                if (toolType != MotionEvent.TOOL_TYPE_STYLUS
+                        && toolType != MotionEvent.TOOL_TYPE_ERASER) {
+                    // The motion event is not from a stylus event, ignore it.
+                    return;
+                }
+                mState.mStylusPointerId = motionEvent.getPointerId(actionIndex);
+                mState.mStylusDownTimeInMillis = motionEvent.getEventTime();
+                mState.mStylusDownX = motionEvent.getX(actionIndex);
+                mState.mStylusDownY = motionEvent.getY(actionIndex);
+                mState.mShouldInitHandwriting = true;
+                mState.mExceedTouchSlop = false;
+                break;
+            case MotionEvent.ACTION_POINTER_UP:
+                final int pointerId = motionEvent.getPointerId(motionEvent.getActionIndex());
+                if (pointerId != mState.mStylusPointerId) {
+                    // ACTION_POINTER_UP is from another stylus pointer, ignore the event.
+                    return;
+                }
+                // Deliberately fall through.
+            case MotionEvent.ACTION_CANCEL:
+            case MotionEvent.ACTION_UP:
+                // If it's ACTION_CANCEL or ACTION_UP, all the pointers go up. There is no need to
+                // check whether the stylus we are tracking goes up.
+                reset();
+                break;
+            case MotionEvent.ACTION_MOVE:
+                // Either we've already tried to initiate handwriting, or the ongoing MotionEvent
+                // sequence is considered to be tap, long-click or other gestures.
+                if (!mState.mShouldInitHandwriting || mState.mExceedTouchSlop) {
+                    return;
+                }
+
+                final long timeElapsed =
+                        motionEvent.getEventTime() - mState.mStylusDownTimeInMillis;
+                if (timeElapsed > mTapTimeoutInMillis) {
+                    reset();
+                    return;
+                }
+
+                final int pointerIndex = motionEvent.findPointerIndex(mState.mStylusPointerId);
+                final float x = motionEvent.getX(pointerIndex);
+                final float y = motionEvent.getY(pointerIndex);
+                if (largerThanTouchSlop(x, y, mState.mStylusDownX, mState.mStylusDownY)) {
+                    mState.mExceedTouchSlop = true;
+                    tryStartHandwriting();
+                }
+        }
+    }
+
+    private View getConnectedView() {
+        if (mConnectedView == null) return null;
+        return mConnectedView.get();
+    }
+
+    /**
+     * Notify HandwritingInitiator that a new InputConnection is created.
+     * The caller of this method should guarantee that each onInputConnectionCreated call
+     * is paired with a onInputConnectionClosed call.
+     * @param view the view that created the current InputConnection.
+     * @see  #onInputConnectionClosed(View)
+     */
+    public void onInputConnectionCreated(@NonNull View view, @NonNull EditorInfo editorInfo) {
+        final View connectedView = getConnectedView();
+//        updateEditorBound(editorInfo.getInitialEditorBound());
+        if (connectedView == view) {
+            ++mConnectionCount;
+        } else {
+            mConnectedView = new WeakReference<>(view);
+            mConnectionCount = 1;
+            tryStartHandwriting();
+        }
+    }
+
+    /**
+     * Notify HandwritingInitiator that the InputConnection has closed for the given view.
+     * The caller of this method should guarantee that each onInputConnectionClosed call
+     * is paired with a onInputConnectionCreated call.
+     * @param view the view that closed the InputConnection.
+     */
+    public void onInputConnectionClosed(@NonNull View view) {
+        final View connectedView = getConnectedView();
+        if (connectedView == view) {
+            --mConnectionCount;
+            if (mConnectionCount == 0) {
+                mConnectedView = null;
+                mEditorBound = null;
+            }
+        } else {
+            // Unexpected branch, set mConnectedView to null to avoid further problem.
+            mConnectedView = null;
+            mEditorBound = null;
+            mConnectionCount = 0;
+        }
+    }
+
+    /**
+     * Notify the HandwritingInitiator that editor bound of the connected view(the view with
+     * active InputConnection) has be updated.
+     * @param editorBound new the editor bounds of the connected view.
+     */
+    public void updateEditorBound(@NonNull Rect editorBound) {
+        if (mEditorBound == null) {
+            mEditorBound = new Rect(editorBound);
+        } else {
+            mEditorBound.left = editorBound.left;
+            mEditorBound.top = editorBound.top;
+            mEditorBound.right = editorBound.right;
+            mEditorBound.bottom = editorBound.bottom;
+        }
+    }
+
+    /**
+     * Try to initiate handwriting. For this method to successfully send startHandwriting signal,
+     * the following 3 conditions should meet:
+     *   a) The stylus movement exceeds the touchSlop.
+     *   b) A View has built InputConnection with IME.
+     *   c) The stylus event lands into the connected View's boundary.
+     * This method will immediately fail without any side effect if condition a or b is not met.
+     * However, if both condition a and b are met but the condition c is not met, it will reset the
+     * internal states. And HandwritingInitiator won't attempt to call startHandwriting until the
+     * next ACTION_DOWN.
+     */
+    private void tryStartHandwriting() {
+        if (!mState.mExceedTouchSlop) {
+            return;
+        }
+        final View connectedView = getConnectedView();
+        if (connectedView == null || mEditorBound == null) {
+            return;
+        }
+        final ViewParent viewParent = connectedView.getParent();
+        // Do a final check before startHandwriting.
+        if (viewParent != null && connectedView.isAttachedToWindow()) {
+            final Rect editorBounds = new Rect(mEditorBound);
+            if (viewParent.getChildVisibleRect(connectedView, editorBounds, null)) {
+                final int roundedInitX = Math.round(mState.mStylusDownX);
+                final int roundedInitY = Math.round(mState.mStylusDownY);
+                if (editorBounds.contains(roundedInitX, roundedInitY)) {
+                    startHandwriting(mConnectedView.get());
+                }
+            }
+        }
+        reset();
+    }
+
+    /** For test only. */
+    @VisibleForTesting
+    public void startHandwriting(View view) {
+        // mImm.startHandwriting(view);
+    }
+
+    private boolean largerThanTouchSlop(float x1, float y1, float x2, float y2) {
+        float dx = x1 - x2;
+        float dy = y1 - y2;
+        return dx * dx + dy * dy > mTouchSlop * mTouchSlop;
+    }
+
+    /** Object that keeps the MotionEvent related states for HandwritingInitiator. */
+    private static class State {
+        /**
+         * Whether it should initiate handwriting mode for the current MotionEvent sequence.
+         * (A series of MotionEvents from ACTION_DOWN to ACTION_UP)
+         *
+         * The purpose of this boolean value is:
+         * a) We should only request to start handwriting mode ONCE for each MotionEvent sequence.
+         * If we've already requested to enter handwriting mode for the ongoing MotionEvent
+         * sequence, this boolean is set to false. And it won't request to start handwriting again.
+         *
+         * b) If the MotionEvent sequence is considered to be tap, long-click or other gestures.
+         * This boolean will be set to false, and it won't request to start handwriting.
+         */
+        private boolean mShouldInitHandwriting = false;
+        /**
+         * Whether the current ongoing stylus MotionEvent sequence already exceeds the touchSlop.
+         * It's used for the case where the stylus exceeds touchSlop before the target View built
+         * InputConnection.
+         */
+        private boolean mExceedTouchSlop = false;
+
+        /** The pointer id of the stylus pointer that is being tracked. */
+        private int mStylusPointerId = -1;
+        /** The time stamp when the stylus pointer goes down. */
+        private long mStylusDownTimeInMillis = -1;
+        /** The initial location where the stylus pointer goes down. */
+        private float mStylusDownX = Float.NaN;
+        private float mStylusDownY = Float.NaN;
+    }
+}
diff --git a/core/java/android/view/InputEventReceiver.java b/core/java/android/view/InputEventReceiver.java
index c9abec9..a24c1f9 100644
--- a/core/java/android/view/InputEventReceiver.java
+++ b/core/java/android/view/InputEventReceiver.java
@@ -79,7 +79,7 @@
         mReceiverPtr = nativeInit(new WeakReference<InputEventReceiver>(this),
                 inputChannel, mMessageQueue);
 
-        mCloseGuard.open("dispose");
+        mCloseGuard.open("InputEventReceiver.dispose");
     }
 
     @Override
diff --git a/core/java/android/view/InputEventSender.java b/core/java/android/view/InputEventSender.java
index d144218..9035f3f 100644
--- a/core/java/android/view/InputEventSender.java
+++ b/core/java/android/view/InputEventSender.java
@@ -67,7 +67,7 @@
         mSenderPtr = nativeInit(new WeakReference<InputEventSender>(this),
                 inputChannel, mMessageQueue);
 
-        mCloseGuard.open("dispose");
+        mCloseGuard.open("InputEventSender.dispose");
     }
 
     @Override
diff --git a/core/java/android/view/InputQueue.java b/core/java/android/view/InputQueue.java
index 7accb66..ff51ebc 100644
--- a/core/java/android/view/InputQueue.java
+++ b/core/java/android/view/InputQueue.java
@@ -52,7 +52,7 @@
     public InputQueue() {
         mPtr = nativeInit(new WeakReference<InputQueue>(this), Looper.myQueue());
 
-        mCloseGuard.open("dispose");
+        mCloseGuard.open("InputQueue.dispose");
     }
 
     @Override
diff --git a/core/java/android/view/InsetsSourceConsumer.java b/core/java/android/view/InsetsSourceConsumer.java
index bf9de39..b1582cf 100644
--- a/core/java/android/view/InsetsSourceConsumer.java
+++ b/core/java/android/view/InsetsSourceConsumer.java
@@ -180,10 +180,7 @@
 
                 // If we have a new leash, make sure visibility is up-to-date, even though we
                 // didn't want to run an animation above.
-                SurfaceControl newLeash = mSourceControl.getLeash();
-                if (oldLeash == null || newLeash == null || !oldLeash.isSameSurface(newLeash)) {
-                    applyHiddenToControl();
-                }
+                applyRequestedVisibilityToControl();
 
                 // Remove the surface that owned by last control when it lost.
                 if (!requestedVisible && !mIsAnimationPending && lastControl == null) {
@@ -388,18 +385,20 @@
         }
     }
 
-    private void applyHiddenToControl() {
+    private void applyRequestedVisibilityToControl() {
         if (mSourceControl == null || mSourceControl.getLeash() == null) {
             return;
         }
 
         final Transaction t = mTransactionSupplier.get();
-        if (DEBUG) Log.d(TAG, "applyHiddenToControl: " + mRequestedVisible);
+        if (DEBUG) Log.d(TAG, "applyRequestedVisibilityToControl: " + mRequestedVisible);
         if (mRequestedVisible) {
             t.show(mSourceControl.getLeash());
         } else {
             t.hide(mSourceControl.getLeash());
         }
+        // Ensure the alpha value is aligned with the actual requested visibility.
+        t.setAlpha(mSourceControl.getLeash(), mRequestedVisible ? 1 : 0);
         t.apply();
         onPerceptible(mRequestedVisible);
     }
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index 8db62f6..adb8b86 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -1872,7 +1872,7 @@
             float x, float y, float pressure, float size, int metaState,
             float xPrecision, float yPrecision, int deviceId, int edgeFlags) {
         return obtain(downTime, eventTime, action, x, y, pressure, size, metaState,
-                xPrecision, yPrecision, deviceId, edgeFlags, InputDevice.SOURCE_CLASS_POINTER,
+                xPrecision, yPrecision, deviceId, edgeFlags, InputDevice.SOURCE_UNKNOWN,
                 DEFAULT_DISPLAY);
     }
 
diff --git a/core/java/android/view/ScrollCaptureConnection.java b/core/java/android/view/ScrollCaptureConnection.java
index 278b2fc..cba0e97 100644
--- a/core/java/android/view/ScrollCaptureConnection.java
+++ b/core/java/android/view/ScrollCaptureConnection.java
@@ -86,7 +86,7 @@
     @Override
     public ICancellationSignal startCapture(@NonNull Surface surface,
             @NonNull IScrollCaptureCallbacks remote) throws RemoteException {
-        mCloseGuard.open("close");
+        mCloseGuard.open("ScrollCaptureConnection.close");
 
         if (!surface.isValid()) {
             throw new RemoteException(new IllegalArgumentException("surface must be valid"));
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index 904aa73..e5ec260 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -755,7 +755,7 @@
     private void setNativeObjectLocked(long ptr) {
         if (mNativeObject != ptr) {
             if (mNativeObject == 0 && ptr != 0) {
-                mCloseGuard.open("release");
+                mCloseGuard.open("Surface.release");
             } else if (mNativeObject != 0 && ptr == 0) {
                 mCloseGuard.close();
             }
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 3b52709..ab33fea 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -515,6 +515,15 @@
     public static final int ENABLE_BACKPRESSURE = 0x00000100;
 
     /**
+     * Buffers from this SurfaceControl should be considered display decorations.
+     *
+     * If the hardware has optimizations for display decorations (e.g. rounded corners, camera
+     * cutouts, etc), it should use them for this layer.
+     * @hide
+     */
+    public static final int DISPLAY_DECORATION = 0x00000200;
+
+    /**
      * Surface creation flag: Creates a surface where color components are interpreted
      * as "non pre-multiplied" by their alpha channel. Of course this flag is
      * meaningless for surfaces without an alpha channel. By default
@@ -3266,6 +3275,21 @@
         }
 
         /**
+         * Sets whether the surface should take advantage of display decoration optimizations.
+         * @hide
+         */
+        public Transaction setDisplayDecoration(SurfaceControl sc, boolean displayDecoration) {
+            checkPreconditions(sc);
+            if (displayDecoration) {
+                nativeSetFlags(mNativeObject, sc.mNativeObject, DISPLAY_DECORATION,
+                        DISPLAY_DECORATION);
+            } else {
+                nativeSetFlags(mNativeObject, sc.mNativeObject, 0, DISPLAY_DECORATION);
+            }
+            return this;
+        }
+
+        /**
          * Indicates whether the surface must be considered opaque, even if its pixel format is
          * set to translucent. This can be useful if an application needs full RGBA 8888 support
          * for instance but will still draw every pixel opaque.
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 3c0597c..49ece5f 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -138,20 +138,9 @@
     private boolean mDisableBackgroundLayer = false;
 
     /**
-     * We use this lock in SOME cases when reading or writing SurfaceControl,
-     * but use the following model so that the RenderThread can run locklessly
-     * in the position up-date case.
-     *
-     * 1. UI Thread can read from mSurfaceControl (use in Transactions) without
-     * holding the lock.
-     * 2. UI Thread will hold the lock when writing to mSurfaceControl (calling release
-     * or remove).
-     * 3. Render thread will also hold the lock when writing to mSurfaceControl (e.g.
-     * calling release from positionLost).
-     * 3. RenderNode.PositionUpdateListener::positionChanged will only be called
-     * when the UI thread is paused (blocked on the Render thread).
-     * 4. positionChanged thus will not be required to hold the lock as the
-     * UI thread is blocked, and the other writer is the RT itself.
+     * We use this lock to protect access to mSurfaceControl and 
+     * SurfaceViewPositionUpdateListener#mPositionChangedTransaction. Both are accessed on the UI
+     * thread and the render thread.
      */
     final Object mSurfaceControlLock = new Object();
     final Rect mTmpRect = new Rect();
@@ -951,7 +940,9 @@
             Transaction geometryTransaction) {
         if (mPositionListener != null) {
             mRenderNode.removePositionUpdateListener(mPositionListener);
-            geometryTransaction = mPositionListener.getTransaction().merge(geometryTransaction);
+            synchronized (mSurfaceControlLock) {
+                geometryTransaction = mPositionListener.getTransaction().merge(geometryTransaction);
+            }
         }
         mPositionListener = new SurfaceViewPositionUpdateListener(surfaceWidth, surfaceHeight,
                 geometryTransaction);
@@ -981,9 +972,9 @@
             mParentSurfaceSequenceId = viewRoot.getSurfaceSequenceId();
 
             if (mViewVisibility) {
-                mTmpTransaction.show(mSurfaceControl);
+                geometryTransaction.show(mSurfaceControl);
             } else {
-                mTmpTransaction.hide(mSurfaceControl);
+                geometryTransaction.hide(mSurfaceControl);
             }
 
             if (mSurfacePackage != null) {
@@ -1480,43 +1471,45 @@
                 if (mSurfaceControl == null) {
                     return;
                 }
-            }
-            if (mRTLastReportedPosition.left == left
-                    && mRTLastReportedPosition.top == top
-                    && mRTLastReportedPosition.right == right
-                    && 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] surfaceSize = %dx%d",
-                            System.identityHashCode(SurfaceView.this), frameNumber,
-                            left, top, right, bottom, mRtSurfaceWidth, mRtSurfaceHeight));
+                if (mRTLastReportedPosition.left == left
+                        && mRTLastReportedPosition.top == top
+                        && mRTLastReportedPosition.right == right
+                        && mRTLastReportedPosition.bottom == bottom
+                        && mRTLastReportedSurfaceSize.x == mRtSurfaceWidth
+                        && mRTLastReportedSurfaceSize.y == mRtSurfaceHeight
+                        && !mPendingTransaction) {
+                    return;
                 }
-                mRTLastReportedPosition.set(left, top, right, bottom);
-                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);
+                try {
+                    if (DEBUG_POSITION) {
+                        Log.d(TAG, String.format(
+                                "%d updateSurfacePosition RenderWorker, frameNr = %d, "
+                                        + "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);
+                    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);
+                    }
+                    final ViewRootImpl viewRoot = getViewRootImpl();
+                    if (viewRoot != null) {
+                        applyChildSurfaceTransaction_renderWorker(mPositionChangedTransaction,
+                                viewRoot.mSurface, frameNumber);
+                    }
+                    applyOrMergeTransaction(mPositionChangedTransaction, frameNumber);
+                    mPendingTransaction = false;
+                } catch (Exception ex) {
+                    Log.e(TAG, "Exception from repositionChild", ex);
                 }
-                final ViewRootImpl viewRoot = getViewRootImpl();
-                if (viewRoot != null) {
-                    applyChildSurfaceTransaction_renderWorker(mPositionChangedTransaction,
-                            viewRoot.mSurface, frameNumber);
-                }
-                applyOrMergeTransaction(mPositionChangedTransaction, frameNumber);
-                mPendingTransaction = false;
-            } catch (Exception ex) {
-                Log.e(TAG, "Exception from repositionChild", ex);
             }
         }
 
@@ -1539,18 +1532,18 @@
             }
             mRTLastReportedPosition.setEmpty();
             mRTLastReportedSurfaceSize.set(-1, -1);
-            if (mPendingTransaction) {
-                Log.w(TAG, System.identityHashCode(SurfaceView.this)
-                        + "Pending transaction cleared.");
-                mPositionChangedTransaction.clear();
-                mPendingTransaction = false;
-            }
 
             /**
              * positionLost can be called while UI thread is un-paused so we
              * need to hold the lock here.
              */
             synchronized (mSurfaceControlLock) {
+                if (mPendingTransaction) {
+                    Log.w(TAG, System.identityHashCode(SurfaceView.this)
+                            + "Pending transaction cleared.");
+                    mPositionChangedTransaction.clear();
+                    mPendingTransaction = false;
+                }
                 if (mSurfaceControl == null) {
                     return;
                 }
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 00754af..1566f9e 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -478,6 +478,19 @@
     }
 
     /**
+     * Remove a frame drawing callback that was added via
+     * {@link #registerRtFrameCallback(FrameDrawingCallback)}
+     *
+     * @param callback The callback to unregister.
+     */
+    void unregisterRtFrameCallback(@NonNull FrameDrawingCallback callback) {
+        if (mNextRtFrameCallbacks == null) {
+            return;
+        }
+        mNextRtFrameCallbacks.remove(callback);
+    }
+
+    /**
      * Destroys all hardware rendering resources associated with the specified
      * view hierarchy.
      *
@@ -679,9 +692,31 @@
         if (mNextRtFrameCallbacks != null) {
             final ArrayList<FrameDrawingCallback> frameCallbacks = mNextRtFrameCallbacks;
             mNextRtFrameCallbacks = null;
-            setFrameCallback(frame -> {
-                for (int i = 0; i < frameCallbacks.size(); ++i) {
-                    frameCallbacks.get(i).onFrameDraw(frame);
+            setFrameCallback(new FrameDrawingCallback() {
+                @Override
+                public void onFrameDraw(long frame) {
+                }
+
+                @Override
+                public FrameCommitCallback onFrameDraw(int syncResult, long frame) {
+                    ArrayList<FrameCommitCallback> frameCommitCallbacks = new ArrayList<>();
+                    for (int i = 0; i < frameCallbacks.size(); ++i) {
+                        FrameCommitCallback frameCommitCallback = frameCallbacks.get(i)
+                                .onFrameDraw(syncResult, frame);
+                        if (frameCommitCallback != null) {
+                            frameCommitCallbacks.add(frameCommitCallback);
+                        }
+                    }
+
+                    if (frameCommitCallbacks.isEmpty()) {
+                        return null;
+                    }
+
+                    return didProduceBuffer -> {
+                        for (int i = 0; i < frameCommitCallbacks.size(); ++i) {
+                            frameCommitCallbacks.get(i).onFrameCommit(didProduceBuffer);
+                        }
+                    };
                 }
             });
         }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 8fda48b..258359e 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -15272,7 +15272,7 @@
      * @param event the KeyEvent object that defines the button action
      */
     public boolean onKeyDown(int keyCode, KeyEvent event) {
-        if (KeyEvent.isConfirmKey(keyCode)) {
+        if (event.hasNoModifiers() && KeyEvent.isConfirmKey(keyCode)) {
             if ((mViewFlags & ENABLED_MASK) == DISABLED) {
                 return true;
             }
@@ -15329,7 +15329,7 @@
      * @param event   The KeyEvent object that defines the button action.
      */
     public boolean onKeyUp(int keyCode, KeyEvent event) {
-        if (KeyEvent.isConfirmKey(keyCode)) {
+        if (event.hasNoModifiers() && KeyEvent.isConfirmKey(keyCode)) {
             if ((mViewFlags & ENABLED_MASK) == DISABLED) {
                 return true;
             }
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index c371202..7718511 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -16,6 +16,8 @@
 
 package android.view;
 
+import static android.graphics.HardwareRenderer.SYNC_CONTEXT_IS_STOPPED;
+import static android.graphics.HardwareRenderer.SYNC_LOST_SURFACE_REWARD_IF_FOUND;
 import static android.os.IInputConstants.INVALID_INPUT_EVENT_ID;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.INVALID_DISPLAY;
@@ -491,6 +493,9 @@
     protected final ViewFrameInfo mViewFrameInfo = new ViewFrameInfo();
     private final InputEventAssigner mInputEventAssigner = new InputEventAssigner();
 
+    // Whether to draw this surface as DISPLAY_DECORATION.
+    boolean mDisplayDecorationCached = false;
+
     /**
      * 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
@@ -747,6 +752,17 @@
         int localChanges;
     }
 
+    private final HandwritingInitiator mHandwritingInitiator;
+
+    /**
+     * Used by InputMethodManager.
+     * @hide
+     */
+    @NonNull
+    public HandwritingInitiator getHandwritingInitiator() {
+        return mHandwritingInitiator;
+    }
+
     /**
      * This is only used on the RenderThread when handling a blast sync. Specifically, it's only
      * used when calling {@link BLASTBufferQueue#setSyncTransaction(Transaction)} and then merged
@@ -821,6 +837,8 @@
                 ? Choreographer.getSfInstance() : Choreographer.getInstance();
         mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
         mInsetsController = new InsetsController(new ViewRootInsetsControllerHost(this));
+        mHandwritingInitiator = new HandwritingInitiator(mViewConfiguration,
+                mContext.getSystemService(InputMethodManager.class));
 
         String processorOverrideName = context.getResources().getString(
                                     R.string.config_inputEventCompatProcessorOverrideClassName);
@@ -1141,7 +1159,7 @@
                 final Rect displayCutoutSafe = mTempRect;
                 state.getDisplayCutoutSafe(displayCutoutSafe);
                 final WindowConfiguration winConfig = getConfiguration().windowConfiguration;
-                mWindowLayout.computeWindowFrames(mWindowAttributes, state,
+                mWindowLayout.computeFrames(mWindowAttributes, state,
                         displayCutoutSafe, winConfig.getBounds(), winConfig.getWindowingMode(),
                         UNSPECIFIED_LENGTH, UNSPECIFIED_LENGTH,
                         mInsetsController.getRequestedVisibilities(),
@@ -1392,11 +1410,20 @@
      */
     public void registerRtFrameCallback(@NonNull FrameDrawingCallback callback) {
         if (mAttachInfo.mThreadedRenderer != null) {
-            mAttachInfo.mThreadedRenderer.registerRtFrameCallback(frame -> {
-                try {
-                    callback.onFrameDraw(frame);
-                } catch (Exception e) {
-                    Log.e(TAG, "Exception while executing onFrameDraw", e);
+            mAttachInfo.mThreadedRenderer.registerRtFrameCallback(new FrameDrawingCallback() {
+                @Override
+                public void onFrameDraw(long frame) {
+                }
+
+                @Override
+                public HardwareRenderer.FrameCommitCallback onFrameDraw(int syncResult,
+                        long frame) {
+                    try {
+                        return callback.onFrameDraw(syncResult, frame);
+                    } catch (Exception e) {
+                        Log.e(TAG, "Exception while executing onFrameDraw", e);
+                    }
+                    return null;
                 }
             });
         }
@@ -1959,26 +1986,29 @@
        return mBoundsLayer;
     }
 
-    Surface getOrCreateBLASTSurface() {
+    void updateBlastSurfaceIfNeeded() {
         if (!mSurfaceControl.isValid()) {
-            return null;
+            return;
         }
 
-        Surface ret = null;
-        if (mBlastBufferQueue == null) {
-            mBlastBufferQueue = new BLASTBufferQueue(mTag, mSurfaceControl,
-                mSurfaceSize.x, mSurfaceSize.y,
-                mWindowAttributes.format);
-            // We only return the Surface the first time, as otherwise
-            // it hasn't changed and there is no need to update.
-            ret = mBlastBufferQueue.createSurface();
-        } else {
+        if (mBlastBufferQueue != null && mBlastBufferQueue.isSameSurfaceControl(mSurfaceControl)) {
             mBlastBufferQueue.update(mSurfaceControl,
                 mSurfaceSize.x, mSurfaceSize.y,
                 mWindowAttributes.format);
+            return;
         }
 
-        return ret;
+        // If the SurfaceControl has been updated, destroy and recreate the BBQ to reset the BQ and
+        // BBQ states.
+        if (mBlastBufferQueue != null) {
+            mBlastBufferQueue.destroy();
+        }
+        mBlastBufferQueue = new BLASTBufferQueue(mTag, mSurfaceControl,
+                mSurfaceSize.x, mSurfaceSize.y, mWindowAttributes.format);
+        Surface blastSurface = mBlastBufferQueue.createSurface();
+        // Only call transferFrom if the surface has changed to prevent inc the generation ID and
+        // causing EGL resources to be recreated.
+        mSurface.transferFrom(blastSurface);
     }
 
     private void setBoundsLayerCrop(Transaction t) {
@@ -2842,6 +2872,12 @@
                 if (mSurfaceControl.isValid()) {
                     updateOpacity(mWindowAttributes, dragResizing,
                             surfaceControlChanged /*forceUpdate */);
+                    // No need to updateDisplayDecoration if it's a new SurfaceControl and
+                    // mDisplayDecorationCached is false, since that's the default for a new
+                    // SurfaceControl.
+                    if (surfaceControlChanged && mDisplayDecorationCached) {
+                        updateDisplayDecoration();
+                    }
                 }
 
                 if (DEBUG_LAYOUT) Log.v(mTag, "relayout: frame=" + frame.toShortString()
@@ -4020,61 +4056,6 @@
         return mAttachInfo.mThreadedRenderer != null && mAttachInfo.mThreadedRenderer.isEnabled();
     }
 
-    private boolean addFrameCompleteCallbackIfNeeded(boolean useBlastSync,
-            boolean reportNextDraw) {
-        if (!isHardwareEnabled()) {
-            return false;
-        }
-
-        if (!useBlastSync && !reportNextDraw) {
-            return false;
-        }
-
-        if (DEBUG_BLAST) {
-            Log.d(mTag, "Creating frameCompleteCallback");
-        }
-
-        final Consumer<SurfaceControl.Transaction> blastSyncConsumer = mBLASTDrawConsumer;
-        mBLASTDrawConsumer = null;
-
-        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.setSyncTransaction(null);
-                // Apply the transactions that were sent to mergeWithNextTransaction since the
-                // frame didn't draw on this vsync. It's possible the frame will draw later, but
-                // it's better to not be sync than to block on a frame that may never come.
-                mBlastBufferQueue.applyPendingTransactions(mRtLastAttemptedDrawFrameNum);
-            }
-
-            Transaction tmpTransaction = new Transaction();
-            tmpTransaction.merge(mRtBLASTSyncTransaction);
-            mHandler.postAtFrontOfQueue(() -> {
-                if (useBlastSync) {
-                    mSurfaceChangedTransaction.merge(tmpTransaction);
-                    if (blastSyncConsumer != null) {
-                        blastSyncConsumer.accept(mSurfaceChangedTransaction);
-                    }
-                }
-
-                if (reportNextDraw) {
-                    pendingDrawFinished();
-                }
-            });
-        });
-        return true;
-    }
-
     private void addFrameCommitCallbackIfNeeded() {
         if (!isHardwareEnabled()) {
             return;
@@ -4105,51 +4086,131 @@
         });
     }
 
-    private void addFrameCallbackIfNeeded(boolean useBlastSync) {
+    private HardwareRenderer.FrameCommitCallback createFrameCommitCallbackForSync(
+            boolean useBlastSync, boolean reportNextDraw, Consumer<Transaction> blastSyncConsumer) {
+        return didProduceBuffer -> {
+            if (DEBUG_BLAST) {
+                Log.d(mTag, "Received frameCommittedCallback "
+                        + " lastAttemptedDrawFrameNum=" + mRtLastAttemptedDrawFrameNum
+                        + " didProduceBuffer=" + didProduceBuffer);
+            }
+
+            // 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 (!didProduceBuffer) {
+                mBlastBufferQueue.setSyncTransaction(null);
+                // Apply the transactions that were sent to mergeWithNextTransaction since the
+                // frame didn't draw on this vsync. It's possible the frame will draw later, but
+                // it's better to not be sync than to block on a frame that may never come.
+                mBlastBufferQueue.applyPendingTransactions(mRtLastAttemptedDrawFrameNum);
+            }
+
+            Transaction tmpTransaction = new Transaction();
+            tmpTransaction.merge(mRtBLASTSyncTransaction);
+            // Post at front of queue so the buffer can be processed immediately and allow RT
+            // to continue processing new buffers. If RT tries to process buffers before the sync
+            // buffer is applied, the new buffers will not get acquired and could result in a
+            // deadlock. UI thread would wait on RT, but RT would be blocked waiting for a free
+            // buffer.
+            mHandler.postAtFrontOfQueue(() -> {
+                if (useBlastSync) {
+                    mSurfaceChangedTransaction.merge(tmpTransaction);
+                    if (blastSyncConsumer != null) {
+                        blastSyncConsumer.accept(mSurfaceChangedTransaction);
+                    }
+                }
+
+                if (reportNextDraw) {
+                    pendingDrawFinished();
+                }
+            });
+        };
+    }
+
+    @Nullable
+    private FrameDrawingCallback createFrameDrawingCallbackIfNeeded(boolean useBlastSync,
+            boolean reportNextDraw) {
+        if (!isHardwareEnabled()) {
+            return null;
+        }
         final boolean hasBlurUpdates = mBlurRegionAggregator.hasUpdates();
         final boolean needsCallbackForBlur = hasBlurUpdates || mBlurRegionAggregator.hasRegions();
 
-        if (!useBlastSync && !needsCallbackForBlur) {
-            return;
+        if (!useBlastSync && !needsCallbackForBlur && !reportNextDraw) {
+            return null;
         }
 
+        final Consumer<SurfaceControl.Transaction> blastSyncConsumer = mBLASTDrawConsumer;
+        mBLASTDrawConsumer = null;
+
         if (DEBUG_BLAST) {
             Log.d(mTag, "Creating frameDrawingCallback"
                     + " nextDrawUseBlastSync=" + useBlastSync
-                    + " hasBlurUpdates=" + hasBlurUpdates);
+                    + " reportNextDraw=" + reportNextDraw
+                    + " hasBlurUpdates=" + hasBlurUpdates
+                    + " hasBlastSyncConsumer=" + (blastSyncConsumer != null));
         }
+
         final BackgroundBlurDrawable.BlurRegion[] blurRegionsForFrame =
                 needsCallbackForBlur ?  mBlurRegionAggregator.getBlurRegionsCopyForRT() : null;
 
         // The callback will run on the render thread.
-        HardwareRenderer.FrameDrawingCallback frameDrawingCallback = frame -> {
-            if (DEBUG_BLAST) {
-                Log.d(mTag, "Received frameDrawingCallback frameNum=" + frame + "."
-                        + " Creating transactionCompleteCallback=" + useBlastSync);
+        return new FrameDrawingCallback() {
+            @Override
+            public void onFrameDraw(long frame) {
             }
 
-            mRtLastAttemptedDrawFrameNum = frame;
+            @Override
+            public HardwareRenderer.FrameCommitCallback onFrameDraw(int syncResult, long frame) {
+                if (DEBUG_BLAST) {
+                    Log.d(mTag,
+                            "Received frameDrawingCallback syncResult=" + syncResult + " frameNum="
+                                    + frame + ".");
+                }
 
-            if (needsCallbackForBlur) {
-                mBlurRegionAggregator
-                    .dispatchBlurTransactionIfNeeded(frame, blurRegionsForFrame, hasBlurUpdates);
-            }
+                mRtLastAttemptedDrawFrameNum = frame;
 
-            if (mBlastBufferQueue == null) {
-                return;
-            }
+                if (needsCallbackForBlur) {
+                    mBlurRegionAggregator.dispatchBlurTransactionIfNeeded(frame,
+                            blurRegionsForFrame, hasBlurUpdates);
+                }
 
-            if (useBlastSync) {
-                // Frame callbacks will always occur after submitting draw requests and before
-                // the draw actually occurs. This will ensure that we set the next transaction
-                // for the frame that's about to get drawn and not on a previous frame that.
+                if (mBlastBufferQueue == null) {
+                    return null;
+                }
 
-                // We don't need to synchronize mRtBLASTSyncTransaction here since it's not
-                // being modified and only sent to BlastBufferQueue.
-                mBlastBufferQueue.setSyncTransaction(mRtBLASTSyncTransaction);
+                if (!useBlastSync && !reportNextDraw) {
+                    return null;
+                }
+
+                // If the syncResults are SYNC_LOST_SURFACE_REWARD_IF_FOUND or
+                // SYNC_CONTEXT_IS_STOPPED it means nothing will draw. There's no need to set up
+                // any blast sync or commit callback, and the code should directly call
+                // pendingDrawFinished.
+                if ((syncResult
+                        & (SYNC_LOST_SURFACE_REWARD_IF_FOUND | SYNC_CONTEXT_IS_STOPPED)) != 0) {
+                    if (reportNextDraw) {
+                        mHandler.postAtFrontOfQueue(() -> pendingDrawFinished());
+                    }
+                    return null;
+                }
+
+                if (DEBUG_BLAST) {
+                    Log.d(mTag, "Setting up sync and frameCommitCallback");
+                }
+
+                if (useBlastSync) {
+                    // Frame callbacks will always occur after submitting draw requests and before
+                    // the draw actually occurs. This will ensure that we set the next transaction
+                    // for the frame that's about to get drawn and not on a previous frame.
+                    mBlastBufferQueue.setSyncTransaction(mRtBLASTSyncTransaction);
+                }
+
+                return createFrameCommitCallbackForSync(useBlastSync, reportNextDraw,
+                        blastSyncConsumer);
             }
         };
-        registerRtFrameCallback(frameDrawingCallback);
     }
 
     private void performDraw(boolean useBlastSync) {
@@ -4165,15 +4226,20 @@
         mIsDrawing = true;
         Trace.traceBegin(Trace.TRACE_TAG_VIEW, "draw");
 
-        addFrameCallbackIfNeeded(useBlastSync);
+        FrameDrawingCallback frameDrawingCallback = createFrameDrawingCallbackIfNeeded(useBlastSync,
+                mReportNextDraw);
+        if (frameDrawingCallback != null) {
+            mAttachInfo.mThreadedRenderer.registerRtFrameCallback(frameDrawingCallback);
+        }
         addFrameCommitCallbackIfNeeded();
-        boolean usingAsyncReport = addFrameCompleteCallbackIfNeeded(useBlastSync, mReportNextDraw);
+        boolean usingAsyncReport = isHardwareEnabled() && (useBlastSync || mReportNextDraw);
 
         try {
             boolean canUseAsync = draw(fullRedrawNeeded);
             if (usingAsyncReport && !canUseAsync) {
-                mAttachInfo.mThreadedRenderer.setFrameCompleteCallback(null);
+                mAttachInfo.mThreadedRenderer.setFrameCallback(null);
                 usingAsyncReport = false;
+                mAttachInfo.mThreadedRenderer.unregisterRtFrameCallback(frameDrawingCallback);
             }
         } finally {
             mIsDrawing = false;
@@ -6365,6 +6431,7 @@
 
         private int processPointerEvent(QueuedInputEvent q) {
             final MotionEvent event = (MotionEvent)q.mEvent;
+            mHandwritingInitiator.onTouchEvent(event);
 
             mAttachInfo.mUnbufferedDispatchRequested = false;
             mAttachInfo.mHandlingPointerEvent = true;
@@ -7543,7 +7610,7 @@
         // When a new focused view is selected, we consume the navigation key because
         // navigation doesn't make much sense unless a view already has focus so
         // the key's purpose is to set focus.
-        if (isNavigationKey(event)) {
+        if (event.hasNoModifiers() && isNavigationKey(event)) {
             return ensureTouchMode(false);
         }
 
@@ -7843,13 +7910,7 @@
             if (!useBLAST()) {
                 mSurface.copyFrom(mSurfaceControl);
             } else {
-                final Surface blastSurface = getOrCreateBLASTSurface();
-                // If blastSurface == null that means it hasn't changed since the last time we
-                // called. In this situation, avoid calling transferFrom as we would then
-                // inc the generation ID and cause EGL resources to be recreated.
-                if (blastSurface != null) {
-                    mSurface.transferFrom(blastSurface);
-                }
+                updateBlastSurfaceIfNeeded();
             }
             if (mAttachInfo.mThreadedRenderer != null) {
                 mAttachInfo.mThreadedRenderer.setSurfaceControl(mSurfaceControl);
@@ -10399,6 +10460,23 @@
     }
 
     /**
+     * @hide
+     */
+    public void setDisplayDecoration(boolean displayDecoration) {
+        if (displayDecoration == mDisplayDecorationCached) return;
+
+        mDisplayDecorationCached = displayDecoration;
+
+        if (mSurfaceControl.isValid()) {
+            updateDisplayDecoration();
+        }
+    }
+
+    private void updateDisplayDecoration() {
+        mTransaction.setDisplayDecoration(mSurfaceControl, mDisplayDecorationCached).apply();
+    }
+
+    /**
      * Sends a list of blur regions to SurfaceFlinger, tagged with a frame.
      *
      * @param regionCopy List of regions
diff --git a/core/java/android/view/WindowLayout.java b/core/java/android/view/WindowLayout.java
index 7dfc95e..e5c7d6d 100644
--- a/core/java/android/view/WindowLayout.java
+++ b/core/java/android/view/WindowLayout.java
@@ -52,7 +52,7 @@
     private final Rect mTempDisplayCutoutSafeExceptMaybeBarsRect = new Rect();
     private final Rect mTempRect = new Rect();
 
-    public boolean computeWindowFrames(WindowManager.LayoutParams attrs, InsetsState state,
+    public boolean computeFrames(WindowManager.LayoutParams attrs, InsetsState state,
             Rect displayCutoutSafe, Rect windowBounds, @WindowingMode int windowingMode,
             int requestedWidth, int requestedHeight, InsetsVisibilities requestedVisibilities,
             Rect attachedWindowFrame, float compatScale, Rect outDisplayFrame, Rect outParentFrame,
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index f69bb6a..cd9f3eb6 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -105,6 +105,7 @@
 import android.os.Build;
 import android.os.Bundle;
 import android.os.IBinder;
+import android.os.IInputConstants;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
@@ -120,6 +121,7 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Objects;
@@ -2755,7 +2757,7 @@
          *
          * <p>Applications that target {@link android.os.Build.VERSION_CODES#P} and later, this flag
          * is ignored unless there is a focused view that returns {@code true} from
-         * {@link View#isInEditMode()} when the window is focused.</p>
+         * {@link View#onCheckIsTextEditor()} when the window is focused.</p>
          */
         public static final int SOFT_INPUT_STATE_VISIBLE = 4;
 
@@ -2765,7 +2767,7 @@
          *
          * <p>Applications that target {@link android.os.Build.VERSION_CODES#P} and later, this flag
          * is ignored unless there is a focused view that returns {@code true} from
-         * {@link View#isInEditMode()} when the window is focused.</p>
+         * {@link View#onCheckIsTextEditor()} when the window is focused.</p>
          */
         public static final int SOFT_INPUT_STATE_ALWAYS_VISIBLE = 5;
 
@@ -3325,21 +3327,13 @@
         public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS = 3;
 
         /**
-         * When this window has focus, disable touch pad pointer gesture processing.
-         * The window will receive raw position updates from the touch pad instead
-         * of pointer movements and synthetic touch events.
-         *
-         * @hide
-         */
-        public static final int INPUT_FEATURE_DISABLE_POINTER_GESTURES = 0x00000001;
-
-        /**
          * Does not construct an input channel for this window.  The channel will therefore
          * be incapable of receiving input.
          *
          * @hide
          */
-        public static final int INPUT_FEATURE_NO_INPUT_CHANNEL = 0x00000002;
+        public static final int INPUT_FEATURE_NO_INPUT_CHANNEL =
+                IInputConstants.InputFeature.NO_INPUT_CHANNEL;
 
         /**
          * When this window has focus, does not call user activity for all input events so
@@ -3352,7 +3346,35 @@
          * @hide
          */
         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-        public static final int INPUT_FEATURE_DISABLE_USER_ACTIVITY = 0x00000004;
+        public static final int INPUT_FEATURE_DISABLE_USER_ACTIVITY =
+                IInputConstants.InputFeature.DISABLE_USER_ACTIVITY;
+
+        /**
+         * An input spy window. This window will receive all pointer events within its touchable
+         * area, but will will not stop events from being sent to other windows below it in z-order.
+         * An input event will be dispatched to all spy windows above the top non-spy window at the
+         * event's coordinates.
+         * @hide
+         */
+        public static final int INPUT_FEATURE_SPY =
+                IInputConstants.InputFeature.SPY;
+
+        /**
+         * When used with the window flag {@link #FLAG_NOT_TOUCHABLE}, this window will continue
+         * to receive events from a stylus device within its touchable region. All other pointer
+         * events, such as from a mouse or touchscreen, will be dispatched to the windows behind it.
+         *
+         * This input feature has no effect when the window flag {@link #FLAG_NOT_TOUCHABLE} is
+         * not set.
+         *
+         * The window must be a trusted overlay to use this input feature.
+         *
+         * @see #FLAG_NOT_TOUCHABLE
+         *
+         * @hide
+         */
+        public static final int INPUT_FEATURE_INTERCEPTS_STYLUS =
+                IInputConstants.InputFeature.INTERCEPTS_STYLUS;
 
         /**
          * An internal annotation for flags that can be specified to {@link #inputFeatures}.
@@ -3361,18 +3383,20 @@
          */
         @Retention(RetentionPolicy.SOURCE)
         @IntDef(flag = true, prefix = { "INPUT_FEATURE_" }, value = {
-            INPUT_FEATURE_DISABLE_POINTER_GESTURES,
             INPUT_FEATURE_NO_INPUT_CHANNEL,
             INPUT_FEATURE_DISABLE_USER_ACTIVITY,
+            INPUT_FEATURE_SPY,
+            INPUT_FEATURE_INTERCEPTS_STYLUS,
         })
         public @interface InputFeatureFlags {}
 
         /**
          * Control special features of the input subsystem.
          *
-         * @see #INPUT_FEATURE_DISABLE_POINTER_GESTURES
          * @see #INPUT_FEATURE_NO_INPUT_CHANNEL
          * @see #INPUT_FEATURE_DISABLE_USER_ACTIVITY
+         * @see #INPUT_FEATURE_SPY
+         * @see #INPUT_FEATURE_INTERCEPTS_STYLUS
          * @hide
          */
         @InputFeatureFlags
@@ -4476,7 +4500,7 @@
                 sb.append(hasSystemUiListeners);
             }
             if (inputFeatures != 0) {
-                sb.append(" if=").append(inputFeatureToString(inputFeatures));
+                sb.append(" if=").append(inputFeaturesToString(inputFeatures));
             }
             if (userActivityTimeout >= 0) {
                 sb.append(" userActivityTimeout=").append(userActivityTimeout);
@@ -4778,17 +4802,28 @@
             }
         }
 
-        private static String inputFeatureToString(int inputFeature) {
-            switch (inputFeature) {
-                case INPUT_FEATURE_DISABLE_POINTER_GESTURES:
-                    return "DISABLE_POINTER_GESTURES";
-                case INPUT_FEATURE_NO_INPUT_CHANNEL:
-                    return "NO_INPUT_CHANNEL";
-                case INPUT_FEATURE_DISABLE_USER_ACTIVITY:
-                    return "DISABLE_USER_ACTIVITY";
-                default:
-                    return Integer.toString(inputFeature);
+        private static String inputFeaturesToString(int inputFeatures) {
+            final List<String> features = new ArrayList<>();
+            if ((inputFeatures & INPUT_FEATURE_NO_INPUT_CHANNEL) != 0) {
+                inputFeatures &= ~INPUT_FEATURE_NO_INPUT_CHANNEL;
+                features.add("INPUT_FEATURE_NO_INPUT_CHANNEL");
             }
+            if ((inputFeatures & INPUT_FEATURE_DISABLE_USER_ACTIVITY) != 0) {
+                inputFeatures &= ~INPUT_FEATURE_DISABLE_USER_ACTIVITY;
+                features.add("INPUT_FEATURE_DISABLE_USER_ACTIVITY");
+            }
+            if ((inputFeatures & INPUT_FEATURE_SPY) != 0) {
+                inputFeatures &= ~INPUT_FEATURE_SPY;
+                features.add("INPUT_FEATURE_SPY");
+            }
+            if ((inputFeatures & INPUT_FEATURE_INTERCEPTS_STYLUS) != 0) {
+                inputFeatures &= ~INPUT_FEATURE_INTERCEPTS_STYLUS;
+                features.add("INPUT_FEATURE_INTERCEPTS_STYLUS");
+            }
+            if (inputFeatures != 0) {
+                features.add(Integer.toHexString(inputFeatures));
+            }
+            return String.join(" | ", features);
         }
 
         /**
diff --git a/core/java/android/view/accessibility/AccessibilityCache.java b/core/java/android/view/accessibility/AccessibilityCache.java
index 91ef8a5..e6385a5 100644
--- a/core/java/android/view/accessibility/AccessibilityCache.java
+++ b/core/java/android/view/accessibility/AccessibilityCache.java
@@ -46,6 +46,8 @@
 
     private static final boolean CHECK_INTEGRITY = Build.IS_ENG;
 
+    private boolean mEnabled = true;
+
     /**
      * {@link AccessibilityEvent} types that are critical for the cache to stay up to date
      *
@@ -98,6 +100,21 @@
         mAccessibilityNodeRefresher = nodeRefresher;
     }
 
+    /** Returns if the cache is enabled. */
+    public boolean isEnabled() {
+        synchronized (mLock) {
+            return mEnabled;
+        }
+    }
+
+    /** Sets enabled status. */
+    public void setEnabled(boolean enabled) {
+        synchronized (mLock) {
+            mEnabled = enabled;
+            clear();
+        }
+    }
+
     /**
      * Sets all {@link AccessibilityWindowInfo}s of all displays into the cache.
      * The key of SparseArray is display ID.
@@ -110,6 +127,12 @@
             SparseArray<List<AccessibilityWindowInfo>> windowsOnAllDisplays,
             long populationTimeStamp) {
         synchronized (mLock) {
+            if (!mEnabled) {
+                if (DEBUG) {
+                    Log.i(LOG_TAG, "Cache is disabled");
+                }
+                return;
+            }
             if (DEBUG) {
                 Log.i(LOG_TAG, "Set windows");
             }
@@ -148,6 +171,12 @@
      */
     public void addWindow(AccessibilityWindowInfo window) {
         synchronized (mLock) {
+            if (!mEnabled) {
+                if (DEBUG) {
+                    Log.i(LOG_TAG, "Cache is disabled");
+                }
+                return;
+            }
             if (DEBUG) {
                 Log.i(LOG_TAG, "Caching window: " + window.getId() + " at display Id [ "
                         + window.getDisplayId() + " ]");
@@ -177,6 +206,12 @@
     public void onAccessibilityEvent(AccessibilityEvent event) {
         AccessibilityNodeInfo nodeToRefresh = null;
         synchronized (mLock) {
+            if (!mEnabled) {
+                if (DEBUG) {
+                    Log.i(LOG_TAG, "Cache is disabled");
+                }
+                return;
+            }
             if (DEBUG) {
                 Log.i(LOG_TAG, "onAccessibilityEvent(" + event + ")");
             }
@@ -292,6 +327,12 @@
      */
     public AccessibilityNodeInfo getNode(int windowId, long accessibilityNodeId) {
         synchronized(mLock) {
+            if (!mEnabled) {
+                if (DEBUG) {
+                    Log.i(LOG_TAG, "Cache is disabled");
+                }
+                return null;
+            }
             LongSparseArray<AccessibilityNodeInfo> nodes = mNodeCache.get(windowId);
             if (nodes == null) {
                 return null;
@@ -309,6 +350,28 @@
         }
     }
 
+    /** Returns {@code true} if {@code info} is in the cache. */
+    public boolean isNodeInCache(AccessibilityNodeInfo info) {
+        if (info == null) {
+            return false;
+        }
+        int windowId = info.getWindowId();
+        long accessibilityNodeId = info.getSourceNodeId();
+        synchronized (mLock) {
+            if (!mEnabled) {
+                if (DEBUG) {
+                    Log.i(LOG_TAG, "Cache is disabled");
+                }
+                return false;
+            }
+            LongSparseArray<AccessibilityNodeInfo> nodes = mNodeCache.get(windowId);
+            if (nodes == null) {
+                return false;
+            }
+            return nodes.get(accessibilityNodeId) != null;
+        }
+    }
+
     /**
      * Gets all {@link AccessibilityWindowInfo}s of all displays from the cache.
      *
@@ -317,6 +380,12 @@
      */
     public SparseArray<List<AccessibilityWindowInfo>> getWindowsOnAllDisplays() {
         synchronized (mLock) {
+            if (!mEnabled) {
+                if (DEBUG) {
+                    Log.i(LOG_TAG, "Cache is disabled");
+                }
+                return null;
+            }
             if (!mIsAllWindowsCached) {
                 return null;
             }
@@ -373,6 +442,12 @@
      */
     public AccessibilityWindowInfo getWindow(int windowId) {
         synchronized (mLock) {
+            if (!mEnabled) {
+                if (DEBUG) {
+                    Log.i(LOG_TAG, "Cache is disabled");
+                }
+                return null;
+            }
             final int displayCounts = mWindowCacheByDisplay.size();
             for (int i = 0; i < displayCounts; i++) {
                 final SparseArray<AccessibilityWindowInfo> windowsOfDisplay =
@@ -397,6 +472,12 @@
      */
     public void add(AccessibilityNodeInfo info) {
         synchronized(mLock) {
+            if (!mEnabled) {
+                if (DEBUG) {
+                    Log.i(LOG_TAG, "Cache is disabled");
+                }
+                return;
+            }
             if (VERBOSE) {
                 Log.i(LOG_TAG, "add(" + info + ")");
             }
@@ -522,6 +603,12 @@
      */
     public AccessibilityNodeInfo getFocus(int focusType, long initialNodeId, int windowId) {
         synchronized (mLock) {
+            if (!mEnabled) {
+                if (DEBUG) {
+                    Log.i(LOG_TAG, "Cache is disabled");
+                }
+                return null;
+            }
             int currentFocusWindowId;
             long currentFocusId;
             if (focusType == FOCUS_ACCESSIBILITY) {
@@ -602,6 +689,23 @@
         mNodeCache.remove(windowId);
     }
 
+    /** Clears a subtree rooted at {@code info}. */
+    public boolean clearSubTree(AccessibilityNodeInfo info) {
+        if (info == null) {
+            return false;
+        }
+        synchronized (mLock) {
+            if (!mEnabled) {
+                if (DEBUG) {
+                    Log.i(LOG_TAG, "Cache is disabled");
+                }
+                return false;
+            }
+            clearSubTreeLocked(info.getWindowId(), info.getSourceNodeId());
+            return true;
+        }
+    }
+
     /**
      * Clears a subtree rooted at the node with the given id that is
      * hosted in a given window.
diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java
index 83712b4..a427ab8 100644
--- a/core/java/android/view/accessibility/AccessibilityEvent.java
+++ b/core/java/android/view/accessibility/AccessibilityEvent.java
@@ -24,7 +24,6 @@
 import android.os.Parcelable;
 import android.text.TextUtils;
 import android.util.Log;
-import android.util.Pools.SynchronizedPool;
 
 import com.android.internal.util.BitUtils;
 
@@ -806,10 +805,6 @@
      */
     public static final int TYPES_ALL_MASK = 0xFFFFFFFF;
 
-    private static final int MAX_POOL_SIZE = 10;
-    private static final SynchronizedPool<AccessibilityEvent> sPool =
-            new SynchronizedPool<>(MAX_POOL_SIZE);
-
     @UnsupportedAppUsage
     private @EventType int mEventType;
     private CharSequence mPackageName;
@@ -1170,7 +1165,7 @@
      */
     public static AccessibilityEvent obtainWindowsChangedEvent(
             int windowId, int windowChangeTypes) {
-        final AccessibilityEvent event = AccessibilityEvent.obtain(TYPE_WINDOWS_CHANGED);
+        final AccessibilityEvent event = new AccessibilityEvent(TYPE_WINDOWS_CHANGED);
         event.setWindowId(windowId);
         event.setWindowChanges(windowChangeTypes);
         event.setImportantForAccessibility(true);
@@ -1178,69 +1173,58 @@
     }
 
     /**
-     * Returns a cached instance if such is available or a new one is
-     * instantiated with its type property set.
+     * Instantiates a new AccessibilityEvent instance with its type property set.
      *
-     * <p>In most situations object pooling is not beneficial. Create a new instance using the
-     * constructor {@link #AccessibilityEvent(int)} instead.
-     *
+     * @deprecated Object pooling has been discontinued. Create a new instance using the
+     * constructor {@link #AccessibilityEvent()} instead.
      * @param eventType The event type.
      * @return An instance.
      */
+    @Deprecated
     public static AccessibilityEvent obtain(int eventType) {
-        AccessibilityEvent event = AccessibilityEvent.obtain();
+        AccessibilityEvent event = new AccessibilityEvent();
         event.setEventType(eventType);
         return event;
     }
 
     /**
-     * Returns a cached instance if such is available or a new one is
-     * created. The returned instance is initialized from the given
+     * Instantiates a new AccessibilityEvent instance.
+     * The returned instance is initialized from the given
      * <code>event</code>.
      *
-     * <p>In most situations object pooling is not beneficial. Create a new instance using the
-     * constructor {@link #AccessibilityEvent(AccessibilityEvent)} instead.
-     *
+     * @deprecated Object pooling has been discontinued. Create a new instance using the
+     * constructor {@link #AccessibilityEvent()} instead.
      * @param event The other event.
      * @return An instance.
      */
+    @Deprecated
     public static AccessibilityEvent obtain(AccessibilityEvent event) {
-        AccessibilityEvent eventClone = AccessibilityEvent.obtain();
+        AccessibilityEvent eventClone = new AccessibilityEvent();
         eventClone.init(event);
         return eventClone;
     }
 
     /**
-     * Returns a cached instance if such is available or a new one is
-     * instantiated.
+     * Instantiates a new AccessibilityEvent instance.
      *
-     * <p>In most situations object pooling is not beneficial. Create a new instance using the
+     * @deprecated Object pooling has been discontinued. Create a new instance using the
      * constructor {@link #AccessibilityEvent()} instead.
-     *
      * @return An instance.
      */
+    @Deprecated
     public static AccessibilityEvent obtain() {
-        AccessibilityEvent event = sPool.acquire();
-        if (event == null) event = new AccessibilityEvent();
-        if (DEBUG_ORIGIN) event.originStackTrace = Thread.currentThread().getStackTrace();
-        return event;
+        return new AccessibilityEvent();
     }
 
     /**
-     * Recycles an instance back to be reused.
-     * <p>
-     *   <b>Note: You must not touch the object after calling this function.</b>
-     * </p>
+     * Previously would recycle an instance back to be reused.
      *
-     * <p>In most situations object pooling is not beneficial, and recycling is not necessary.
-     *
-     * @throws IllegalStateException If the event is already recycled.
+     * @deprecated Object pooling has been discontinued. Calling this function now will have
+     * no effect.
      */
     @Override
-    public void recycle() {
-        clear();
-        sPool.release(this);
-    }
+    @Deprecated
+    public void recycle() {}
 
     /**
      * Clears the state of this instance.
@@ -1260,7 +1244,6 @@
         if (mRecords != null) {
             while (!mRecords.isEmpty()) {
                 AccessibilityRecord record = mRecords.remove(0);
-                record.recycle();
             }
         }
         if (DEBUG_ORIGIN) originStackTrace = null;
@@ -1288,7 +1271,7 @@
         if (recordCount > 0) {
             mRecords = new ArrayList<>(recordCount);
             for (int i = 0; i < recordCount; i++) {
-                AccessibilityRecord record = AccessibilityRecord.obtain();
+                AccessibilityRecord record = new AccessibilityRecord();
                 readAccessibilityRecordFromParcel(record, parcel);
                 record.mConnectionId = mConnectionId;
                 mRecords.add(record);
@@ -1527,7 +1510,7 @@
     public static final @android.annotation.NonNull Parcelable.Creator<AccessibilityEvent> CREATOR =
             new Parcelable.Creator<AccessibilityEvent>() {
         public AccessibilityEvent createFromParcel(Parcel parcel) {
-            AccessibilityEvent event = AccessibilityEvent.obtain();
+            AccessibilityEvent event = new AccessibilityEvent();
             event.initFromParcel(parcel);
             return event;
         }
diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
index dc4c59a..6f4bc71 100644
--- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java
+++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
@@ -18,6 +18,7 @@
 
 import static android.accessibilityservice.AccessibilityTrace.FLAGS_ACCESSIBILITY_INTERACTION_CLIENT;
 import static android.accessibilityservice.AccessibilityTrace.FLAGS_ACCESSIBILITY_INTERACTION_CONNECTION_CALLBACK;
+import static android.os.Build.VERSION_CODES.S;
 
 import android.accessibilityservice.IAccessibilityServiceConnection;
 import android.annotation.NonNull;
@@ -225,6 +226,9 @@
      */
     public static void addConnection(int connectionId, IAccessibilityServiceConnection connection,
             boolean initializeCache) {
+        if (connectionId == NO_ID) {
+            return;
+        }
         synchronized (sConnectionCache) {
             sConnectionCache.put(connectionId, connection);
             if (!initializeCache) {
@@ -554,6 +558,10 @@
                             }
                             return cachedInfo;
                         }
+                        if (!cache.isEnabled()) {
+                            // Skip prefetching if cache is disabled.
+                            prefetchFlags &= ~AccessibilityNodeInfo.FLAG_PREFETCH_MASK;
+                        }
                         if (DEBUG) {
                             Log.i(LOG_TAG, "Node cache miss for "
                                     + idToString(accessibilityWindowId, accessibilityNodeId));
@@ -970,9 +978,9 @@
     /**
      * Clears the cache associated with {@code connectionId}
      * @param connectionId the connection id
-     * TODO(207417185): Modify UnsupportedAppUsage
      */
-    @UnsupportedAppUsage()
+    @UnsupportedAppUsage(maxTargetSdk = S, publicAlternatives =
+            "{@link android.accessibilityservice.AccessibilityService#clearCache()}")
     public void clearCache(int connectionId) {
         AccessibilityCache cache = getCache(connectionId);
         if (cache == null) {
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 9511958..db7c663 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -50,7 +50,6 @@
 import android.util.ArraySet;
 import android.util.Log;
 import android.util.LongArray;
-import android.util.Pools.SynchronizedPool;
 import android.util.Size;
 import android.util.TypedValue;
 import android.view.SurfaceView;
@@ -68,7 +67,6 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
-import java.util.concurrent.atomic.AtomicInteger;
 
 /**
  * This class represents a node of the window content as well as actions that
@@ -723,9 +721,6 @@
      */
     private static final int VIRTUAL_DESCENDANT_ID_SHIFT = 32;
 
-    // TODO(b/129300068): Remove sNumInstancesInUse.
-    private static AtomicInteger sNumInstancesInUse;
-
     /**
      * Gets the accessibility view id which identifies a View in the view three.
      *
@@ -769,11 +764,6 @@
         return (((long) virtualDescendantId) << VIRTUAL_DESCENDANT_ID_SHIFT) | accessibilityViewId;
     }
 
-    // Housekeeping.
-    private static final int MAX_POOL_SIZE = 50;
-    private static final SynchronizedPool<AccessibilityNodeInfo> sPool =
-            new SynchronizedPool<>(MAX_POOL_SIZE);
-
     private static final AccessibilityNodeInfo DEFAULT = new AccessibilityNodeInfo();
 
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@@ -869,7 +859,7 @@
      * @param info The other info.
      */
     public AccessibilityNodeInfo(@NonNull AccessibilityNodeInfo info) {
-        init(info, false /* usePoolingInfo */);
+        init(info);
     }
 
     /**
@@ -1009,13 +999,7 @@
         if (refreshedInfo == null) {
             return false;
         }
-        // Hard-to-reproduce bugs seem to be due to some tools recycling a node on another
-        // thread. If that happens, the init will re-seal the node, which then is in a bad state
-        // when it is obtained. Enforce sealing again before we init to fail when a node has been
-        // recycled during a refresh to catch such errors earlier.
-        enforceSealed();
-        init(refreshedInfo, true /* usePoolingInfo */);
-        refreshedInfo.recycle();
+        init(refreshedInfo);
         return true;
     }
 
@@ -3599,25 +3583,23 @@
      * Returns a cached instance if such is available otherwise a new one
      * and sets the source.
      *
-     * <p>In most situations object pooling is not beneficial. Create a new instance using the
+     * @deprecated Object pooling has been discontinued. Create a new instance using the
      * constructor {@link #AccessibilityNodeInfo(View)} instead.
-     *
      * @param source The source view.
      * @return An instance.
      *
      * @see #setSource(View)
      */
+    @Deprecated
     public static AccessibilityNodeInfo obtain(View source) {
-        AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
-        info.setSource(source);
-        return info;
+        return new AccessibilityNodeInfo(source);
     }
 
     /**
      * Returns a cached instance if such is available otherwise a new one
      * and sets the source.
      *
-     * <p>In most situations object pooling is not beneficial. Create a new instance using the
+     * @deprecated Object pooling has been discontinued. Create a new instance using the
      * constructor {@link #AccessibilityNodeInfo(View, int)} instead.
      *
      * @param root The root of the virtual subtree.
@@ -3626,71 +3608,45 @@
      *
      * @see #setSource(View, int)
      */
+    @Deprecated
     public static AccessibilityNodeInfo obtain(View root, int virtualDescendantId) {
-        AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
-        info.setSource(root, virtualDescendantId);
-        return info;
+        return new AccessibilityNodeInfo(root, virtualDescendantId);
     }
 
     /**
-     * Returns a cached instance if such is available otherwise a new one.
+     * Instantiates a new AccessibilityNodeInfo.
      *
-     * <p>In most situations object pooling is not beneficial. Create a new instance using the
+     * @deprecated Object pooling has been discontinued. Create a new instance using the
      * constructor {@link #AccessibilityNodeInfo()} instead.
-     *
      * @return An instance.
      */
+    @Deprecated
     public static AccessibilityNodeInfo obtain() {
-        AccessibilityNodeInfo info = sPool.acquire();
-        if (sNumInstancesInUse != null) {
-            sNumInstancesInUse.incrementAndGet();
-        }
-        return (info != null) ? info : new AccessibilityNodeInfo();
+        return new AccessibilityNodeInfo();
     }
 
     /**
-     * Returns a cached instance if such is available or a new one is
-     * create. The returned instance is initialized from the given
+     * Instantiates a new AccessibilityNodeInfo initialized from the given
      * <code>info</code>.
      *
-     * <p>In most situations object pooling is not beneficial. Create a new instance using the
+     * @deprecated Object pooling has been discontinued. Create a new instance using the
      * constructor {@link #AccessibilityNodeInfo(AccessibilityNodeInfo)} instead.
-     *
      * @param info The other info.
      * @return An instance.
      */
+    @Deprecated
     public static AccessibilityNodeInfo obtain(AccessibilityNodeInfo info) {
-        AccessibilityNodeInfo infoClone = AccessibilityNodeInfo.obtain();
-        infoClone.init(info, true /* usePoolingInfo */);
-        return infoClone;
+        return new AccessibilityNodeInfo(info);
     }
 
     /**
-     * Return an instance back to be reused.
-     * <p>
-     * <strong>Note:</strong> You must not touch the object after calling this function.
+     * Would previously return an instance back to be reused.
      *
-     * <p>In most situations object pooling is not beneficial, and recycling is not necessary.
-     *
-     * @throws IllegalStateException If the info is already recycled.
+     * @deprecated Object pooling has been discontinued. Calling this function now will have
+     * no effect.
      */
-    public void recycle() {
-        clear();
-        sPool.release(this);
-        if (sNumInstancesInUse != null) {
-            sNumInstancesInUse.decrementAndGet();
-        }
-    }
-
-    /**
-     * Specify a counter that will be incremented on obtain() and decremented on recycle()
-     *
-     * @hide
-     */
-    @TestApi
-    public static void setNumInstancesInUseCounter(AtomicInteger counter) {
-        sNumInstancesInUse = counter;
-    }
+    @Deprecated
+    public void recycle() {}
 
     /**
      * {@inheritDoc}
@@ -3704,7 +3660,6 @@
         writeToParcelNoRecycle(parcel, flags);
         // Since instances of this class are fetched via synchronous i.e. blocking
         // calls in IPCs we always recycle as soon as the instance is marshaled.
-        recycle();
     }
 
     /** @hide */
@@ -4000,9 +3955,8 @@
      * Initializes this instance from another one.
      *
      * @param other The other instance.
-     * @param usePoolingInfos whether using pooled object internally or not
      */
-    private void init(AccessibilityNodeInfo other, boolean usePoolingInfos) {
+    private void init(AccessibilityNodeInfo other) {
         mSealed = other.mSealed;
         mSourceNodeId = other.mSourceNodeId;
         mParentNodeId = other.mParentNodeId;
@@ -4062,11 +4016,7 @@
 
         mExtras = other.mExtras != null ? new Bundle(other.mExtras) : null;
 
-        if (usePoolingInfos) {
-            initPoolingInfos(other);
-        } else {
-            initCopyInfos(other);
-        }
+        initCopyInfos(other);
 
         final TouchDelegateInfo otherInfo = other.mTouchDelegateInfo;
         mTouchDelegateInfo = (otherInfo != null)
@@ -4077,21 +4027,6 @@
         mLeashedParentNodeId = other.mLeashedParentNodeId;
     }
 
-    private void initPoolingInfos(AccessibilityNodeInfo other) {
-        if (mRangeInfo != null) mRangeInfo.recycle();
-        mRangeInfo = (other.mRangeInfo != null)
-                ? RangeInfo.obtain(other.mRangeInfo) : null;
-        if (mCollectionInfo != null) mCollectionInfo.recycle();
-        mCollectionInfo = (other.mCollectionInfo != null)
-                ? CollectionInfo.obtain(other.mCollectionInfo) : null;
-        if (mCollectionItemInfo != null) mCollectionItemInfo.recycle();
-        mCollectionItemInfo =  (other.mCollectionItemInfo != null)
-                ? CollectionItemInfo.obtain(other.mCollectionItemInfo) : null;
-        if (mExtraRenderingInfo != null) mExtraRenderingInfo.recycle();
-        mExtraRenderingInfo = (other.mExtraRenderingInfo != null)
-                ? ExtraRenderingInfo.obtain(other.mExtraRenderingInfo) : null;
-    }
-
     private void initCopyInfos(AccessibilityNodeInfo other) {
         RangeInfo ri = other.mRangeInfo;
         mRangeInfo = (ri == null) ? null
@@ -4205,27 +4140,24 @@
                 ? parcel.readBundle()
                 : null;
 
-        if (mRangeInfo != null) mRangeInfo.recycle();
         mRangeInfo = isBitSet(nonDefaultFields, fieldIndex++)
-                ? RangeInfo.obtain(
+                ? new RangeInfo(
                         parcel.readInt(),
                         parcel.readFloat(),
                         parcel.readFloat(),
                         parcel.readFloat())
                 : null;
 
-        if (mCollectionInfo != null) mCollectionInfo.recycle();
         mCollectionInfo = isBitSet(nonDefaultFields, fieldIndex++)
-                ? CollectionInfo.obtain(
+                ? new CollectionInfo(
                         parcel.readInt(),
                         parcel.readInt(),
                         parcel.readInt() == 1,
                         parcel.readInt())
                 : null;
 
-        if (mCollectionItemInfo != null) mCollectionItemInfo.recycle();
         mCollectionItemInfo = isBitSet(nonDefaultFields, fieldIndex++)
-                ? CollectionItemInfo.obtain(
+                ? new CollectionItemInfo(
                         parcel.readString(),
                         parcel.readInt(),
                         parcel.readInt(),
@@ -4241,8 +4173,7 @@
         }
 
         if (isBitSet(nonDefaultFields, fieldIndex++)) {
-            if (mExtraRenderingInfo != null) mExtraRenderingInfo.recycle();
-            mExtraRenderingInfo = ExtraRenderingInfo.obtain();
+            mExtraRenderingInfo = new ExtraRenderingInfo(null);
             mExtraRenderingInfo.mLayoutSize = (Size) parcel.readValue(null);
             mExtraRenderingInfo.mTextSizeInPx = parcel.readFloat();
             mExtraRenderingInfo.mTextSizeUnit = parcel.readInt();
@@ -4265,7 +4196,7 @@
      * Clears the state of this instance.
      */
     private void clear() {
-        init(DEFAULT, true /* usePoolingInfo */);
+        init(DEFAULT);
     }
 
     private static boolean isDefaultStandardAction(AccessibilityAction action) {
@@ -5235,7 +5166,6 @@
      * handled by the {@link AccessibilityNodeInfo} to which this object is attached.
      */
     public static final class RangeInfo {
-        private static final int MAX_POOL_SIZE = 10;
 
         /** Range type: integer. */
         public static final int RANGE_TYPE_INT = 0;
@@ -5244,35 +5174,16 @@
         /** Range type: percent with values from zero to one hundred. */
         public static final int RANGE_TYPE_PERCENT = 2;
 
-        private static final SynchronizedPool<RangeInfo> sPool =
-                new SynchronizedPool<AccessibilityNodeInfo.RangeInfo>(MAX_POOL_SIZE);
-
         private int mType;
         private float mMin;
         private float mMax;
         private float mCurrent;
-
         /**
-         * Obtains a pooled instance that is a clone of another one.
+         * Instantiates a new RangeInfo.
          *
-         * <p>In most situations object pooling is not beneficial. Create a new instance using the
-         * constructor {@link AccessibilityNodeInfo.RangeInfo#RangeInfo(int,
-         * float, float, float)} instead.
-         *
-         * @param other The instance to clone.
-         *
-         * @hide
-         */
-        public static RangeInfo obtain(RangeInfo other) {
-            return obtain(other.mType, other.mMin, other.mMax, other.mCurrent);
-        }
-
-        /**
-         * Obtains a pooled instance.
-         *
-         * <p>In most situations object pooling is not beneficial. Create a new instance using the
-         * constructor {@link AccessibilityNodeInfo.RangeInfo#RangeInfo(int,
-         * float, float, float)} instead.
+         * @deprecated Object pooling has been discontinued. Create a new instance using the
+         * constructor {@link AccessibilityNodeInfo.RangeInfo#RangeInfo(int, float, float,
+         * float)} instead.
          *
          * @param type The type of the range.
          * @param min The minimum value. Use {@code Float.NEGATIVE_INFINITY} if the range has no
@@ -5281,17 +5192,9 @@
          *            maximum.
          * @param current The current value.
          */
+        @Deprecated
         public static RangeInfo obtain(int type, float min, float max, float current) {
-            RangeInfo info = sPool.acquire();
-            if (info == null) {
-                return new RangeInfo(type, min, max, current);
-            }
-
-            info.mType = type;
-            info.mMin = min;
-            info.mMax = max;
-            info.mCurrent = current;
-            return info;
+            return new RangeInfo(type, min, max, current);
         }
 
         /**
@@ -5354,12 +5257,11 @@
         /**
          * Recycles this instance.
          *
-         * <p>In most situations object pooling is not beneficial, and recycling is not necessary.
+         * @deprecated Object pooling has been discontinued. Calling this function now will have
+         * no effect.
          */
-        void recycle() {
-            clear();
-            sPool.release(this);
-        }
+        @Deprecated
+        void recycle() {}
 
         private void clear() {
             mType = 0;
@@ -5392,20 +5294,15 @@
         /** Selection mode where multiple items may be selected. */
         public static final int SELECTION_MODE_MULTIPLE = 2;
 
-        private static final int MAX_POOL_SIZE = 20;
-
-        private static final SynchronizedPool<CollectionInfo> sPool =
-                new SynchronizedPool<>(MAX_POOL_SIZE);
-
         private int mRowCount;
         private int mColumnCount;
         private boolean mHierarchical;
         private int mSelectionMode;
 
         /**
-         * Obtains a pooled instance that is a clone of another one.
+         * Instantiates a CollectionInfo that is a clone of another one.
          *
-         * <p>In most situations object pooling is not beneficial. Create a new instance using the
+         * @deprecated Object pooling has been discontinued. Create a new instance using the
          * constructor {@link
          * AccessibilityNodeInfo.CollectionInfo#CollectionInfo} instead.
          *
@@ -5413,14 +5310,14 @@
          * @hide
          */
         public static CollectionInfo obtain(CollectionInfo other) {
-            return CollectionInfo.obtain(other.mRowCount, other.mColumnCount, other.mHierarchical,
+            return new CollectionInfo(other.mRowCount, other.mColumnCount, other.mHierarchical,
                     other.mSelectionMode);
         }
 
         /**
          * Obtains a pooled instance.
          *
-         * <p>In most situations object pooling is not beneficial. Create a new instance using the
+         * @deprecated Object pooling has been discontinued. Create a new instance using the
          * constructor {@link
          * AccessibilityNodeInfo.CollectionInfo#CollectionInfo(int, int,
          * boolean)} instead.
@@ -5431,13 +5328,13 @@
          */
         public static CollectionInfo obtain(int rowCount, int columnCount,
                 boolean hierarchical) {
-            return obtain(rowCount, columnCount, hierarchical, SELECTION_MODE_NONE);
+            return new CollectionInfo(rowCount, columnCount, hierarchical, SELECTION_MODE_NONE);
         }
 
         /**
          * Obtains a pooled instance.
          *
-         * <p>In most situations object pooling is not beneficial. Create a new instance using the
+         * @deprecated Object pooling has been discontinued. Create a new instance using the
          * constructor {@link
          * AccessibilityNodeInfo.CollectionInfo#CollectionInfo(int, int,
          * boolean, int)} instead.
@@ -5454,16 +5351,7 @@
          */
         public static CollectionInfo obtain(int rowCount, int columnCount,
                 boolean hierarchical, int selectionMode) {
-           final CollectionInfo info = sPool.acquire();
-            if (info == null) {
-                return new CollectionInfo(rowCount, columnCount, hierarchical, selectionMode);
-            }
-
-            info.mRowCount = rowCount;
-            info.mColumnCount = columnCount;
-            info.mHierarchical = hierarchical;
-            info.mSelectionMode = selectionMode;
-            return info;
+            return new CollectionInfo(rowCount, columnCount, hierarchical, selectionMode);
         }
 
         /**
@@ -5535,14 +5423,13 @@
         }
 
         /**
-         * Recycles this instance.
+         * Previously would recycle this instance.
          *
-         * <p>In most situations object pooling is not beneficial, and recycling is not necessary.
+         * @deprecated Object pooling has been discontinued. Calling this function now will have
+         * no effect.
          */
-        void recycle() {
-            clear();
-            sPool.release(this);
-        }
+        @Deprecated
+        void recycle() {}
 
         private void clear() {
             mRowCount = 0;
@@ -5566,15 +5453,10 @@
      * </p>
      */
     public static final class CollectionItemInfo {
-        private static final int MAX_POOL_SIZE = 20;
-
-        private static final SynchronizedPool<CollectionItemInfo> sPool =
-                new SynchronizedPool<>(MAX_POOL_SIZE);
-
         /**
-         * Obtains a pooled instance that is a clone of another one.
+         * Instantiates a CollectionItemInfo that is a clone of another one.
          *
-         * <p>In most situations object pooling is not beneficial. Create a new instance using the
+         * @deprecated Object pooling has been discontinued. Create a new instance using the
          * constructor {@link
          * AccessibilityNodeInfo.CollectionItemInfo#CollectionItemInfo}
          * instead.
@@ -5582,20 +5464,20 @@
          * @param other The instance to clone.
          * @hide
          */
+        @Deprecated
         public static CollectionItemInfo obtain(CollectionItemInfo other) {
-            return CollectionItemInfo.obtain(other.mRowTitle, other.mRowIndex, other.mRowSpan,
-                    other.mColumnTitle, other.mColumnIndex, other.mColumnSpan, other.mHeading,
-                    other.mSelected);
+            return new CollectionItemInfo(other.mRowTitle, other.mRowIndex, other.mRowSpan,
+                other.mColumnTitle, other.mColumnIndex, other.mColumnSpan, other.mHeading,
+                other.mSelected);
         }
 
         /**
-         * Obtains a pooled instance.
+         * Instantiates a new CollectionItemInfo.
          *
-         * <p>In most situations object pooling is not beneficial. Create a new instance using the
+         * @deprecated Object pooling has been discontinued. Create a new instance using the
          * constructor {@link
          * AccessibilityNodeInfo.CollectionItemInfo#CollectionItemInfo(int,
          * int, int, int, boolean)} instead.
-         *
          * @param rowIndex The row index at which the item is located.
          * @param rowSpan The number of rows the item spans.
          * @param columnIndex The column index at which the item is located.
@@ -5603,37 +5485,39 @@
          * @param heading Whether the item is a heading. (Prefer
          *                {@link AccessibilityNodeInfo#setHeading(boolean)}).
          */
+        @Deprecated
         public static CollectionItemInfo obtain(int rowIndex, int rowSpan,
                 int columnIndex, int columnSpan, boolean heading) {
-            return obtain(rowIndex, rowSpan, columnIndex, columnSpan, heading, false);
+            return new CollectionItemInfo(rowIndex, rowSpan, columnIndex, columnSpan, heading,
+                false);
         }
 
         /**
-         * Obtains a pooled instance.
+         * Instantiates a new CollectionItemInfo.
          *
-         * <p>In most situations object pooling is not beneficial. Creates a new instance using the
+         * @deprecated Object pooling has been discontinued. Create a new instance using the
          * constructor {@link
          * AccessibilityNodeInfo.CollectionItemInfo#CollectionItemInfo(int,
-         * int, int, int, boolean, boolean)} instead.
-         *
+         * int, int, int, boolean)} instead.
          * @param rowIndex The row index at which the item is located.
          * @param rowSpan The number of rows the item spans.
          * @param columnIndex The column index at which the item is located.
          * @param columnSpan The number of columns the item spans.
          * @param heading Whether the item is a heading. (Prefer
-         *                {@link AccessibilityNodeInfo#setHeading(boolean)})
+         *                {@link AccessibilityNodeInfo#setHeading(boolean)}).
          * @param selected Whether the item is selected.
          */
+        @Deprecated
         public static CollectionItemInfo obtain(int rowIndex, int rowSpan,
                 int columnIndex, int columnSpan, boolean heading, boolean selected) {
-            return obtain(null, rowIndex, rowSpan, null, columnIndex,
-                    columnSpan, heading, selected);
+            return new CollectionItemInfo(rowIndex, rowSpan, columnIndex, columnSpan, heading,
+                selected);
         }
 
         /**
-         * Obtains a pooled instance.
+         * Instantiates a new CollectionItemInfo.
          *
-         * <p>In most situations object pooling is not beneficial. Creates a new instance using the
+         * @deprecated Object pooling has been discontinued. Creates a new instance using the
          * constructor {@link
          * AccessibilityNodeInfo.CollectionItemInfo#CollectionItemInfo(int,
          * int, int, int, boolean, boolean)} instead.
@@ -5648,25 +5532,13 @@
          *                {@link AccessibilityNodeInfo#setHeading(boolean)})
          * @param selected Whether the item is selected.
          */
+        @Deprecated
         @NonNull
         public static CollectionItemInfo obtain(@Nullable String rowTitle, int rowIndex,
                 int rowSpan, @Nullable String columnTitle, int columnIndex, int columnSpan,
                 boolean heading, boolean selected) {
-            final CollectionItemInfo info = sPool.acquire();
-            if (info == null) {
-                return new CollectionItemInfo(rowTitle, rowIndex, rowSpan, columnTitle,
-                        columnIndex, columnSpan, heading, selected);
-            }
-
-            info.mRowIndex = rowIndex;
-            info.mRowSpan = rowSpan;
-            info.mColumnIndex = columnIndex;
-            info.mColumnSpan = columnSpan;
-            info.mHeading = heading;
-            info.mSelected = selected;
-            info.mRowTitle = rowTitle;
-            info.mColumnTitle = columnTitle;
-            return info;
+            return new CollectionItemInfo(rowTitle, rowIndex, rowSpan, columnTitle, columnIndex,
+                columnSpan, heading, selected);
         }
 
         private boolean mHeading;
@@ -5817,12 +5689,11 @@
         /**
          * Recycles this instance.
          *
-         * <p>In most situations object pooling is not beneficial, and recycling is not necessary.
+         * @deprecated Object pooling has been discontinued. Calling this function now will have
+         * no effect.
          */
-        void recycle() {
-            clear();
-            sPool.release(this);
-        }
+        @Deprecated
+        void recycle() {}
 
         private void clear() {
             mColumnIndex = 0;
@@ -6151,34 +6022,34 @@
      */
     public static final class ExtraRenderingInfo {
         private static final int UNDEFINED_VALUE = -1;
-        private static final int MAX_POOL_SIZE = 20;
-        private static final SynchronizedPool<ExtraRenderingInfo> sPool =
-                new SynchronizedPool<>(MAX_POOL_SIZE);
 
         private Size mLayoutSize;
         private float mTextSizeInPx = UNDEFINED_VALUE;
         private int mTextSizeUnit = UNDEFINED_VALUE;
 
         /**
-         * Obtains a pooled instance.
+         * Instantiates an ExtraRenderingInfo, by copying an existing one.
+         *
          * @hide
+         * @deprecated Object pooling has been discontinued. Create a new instance using the
+         * constructor {@link #ExtraRenderingInfo(ExtraRenderingInfo)} instead.
          */
+        @Deprecated
         @NonNull
         public static ExtraRenderingInfo obtain() {
-            final ExtraRenderingInfo info = sPool.acquire();
-            if (info == null) {
-                return new ExtraRenderingInfo(null);
-            }
-            return info;
+            return new ExtraRenderingInfo(null);
         }
 
-        /** Obtains a pooled instance that is a clone of another one. */
+        /**
+         * Instantiates an ExtraRenderingInfo, by copying an existing one.
+         *
+         * @deprecated Object pooling has been discontinued. Create a new instance using the
+         * constructor {@link #ExtraRenderingInfo(ExtraRenderingInfo)} instead.
+         * @param other
+         */
+        @Deprecated
         private static ExtraRenderingInfo obtain(ExtraRenderingInfo other) {
-            ExtraRenderingInfo extraRenderingInfo = ExtraRenderingInfo.obtain();
-            extraRenderingInfo.mLayoutSize = other.mLayoutSize;
-            extraRenderingInfo.mTextSizeInPx = other.mTextSizeInPx;
-            extraRenderingInfo.mTextSizeUnit = other.mTextSizeUnit;
-            return extraRenderingInfo;
+            return new ExtraRenderingInfo(other);
         }
 
         /**
@@ -6268,14 +6139,13 @@
         }
 
         /**
-         * Recycles this instance.
+         * Previously would recycle this instance.
          *
-         * <p>In most situations object pooling is not beneficial, and recycling is not necessary.
+         * @deprecated Object pooling has been discontinued. Calling this function now will have
+         * no effect.
          */
-        void recycle() {
-            clear();
-            sPool.release(this);
-        }
+        @Deprecated
+        void recycle() {}
 
         private void clear() {
             mLayoutSize = null;
@@ -6291,7 +6161,7 @@
             new Parcelable.Creator<AccessibilityNodeInfo>() {
         @Override
         public AccessibilityNodeInfo createFromParcel(Parcel parcel) {
-            AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
+            AccessibilityNodeInfo info = new AccessibilityNodeInfo();
             info.initFromParcel(parcel);
             return info;
         }
diff --git a/core/java/android/view/accessibility/AccessibilityRecord.java b/core/java/android/view/accessibility/AccessibilityRecord.java
index f26abb2..426a3f4 100644
--- a/core/java/android/view/accessibility/AccessibilityRecord.java
+++ b/core/java/android/view/accessibility/AccessibilityRecord.java
@@ -78,13 +78,6 @@
         | AccessibilityNodeInfo.FLAG_PREFETCH_SIBLINGS
         | AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS;
 
-    // Housekeeping
-    private static final int MAX_POOL_SIZE = 10;
-    private static final Object sPoolLock = new Object();
-    private static AccessibilityRecord sPool;
-    private static int sPoolSize;
-    private AccessibilityRecord mNext;
-    private boolean mIsInPool;
 
     @UnsupportedAppUsage
     boolean mSealed;
@@ -821,15 +814,14 @@
     }
 
     /**
-     * Returns a cached instance if such is available or a new one is
-     * instantiated. The instance is initialized with data from the
+     * Instantiates a new record initialized with data from the
      * given record.
      *
-     * <p>In most situations object pooling is not beneficial. Create a new instance using the
-     * constructor {@link #AccessibilityRecord(AccessibilityRecord)} instead.
-     *
+     * @deprecated Object pooling has been discontinued. Create a new instance using the
+     * constructor {@link #AccessibilityRecord()} instead.
      * @return An instance.
      */
+    @Deprecated
     public static AccessibilityRecord obtain(AccessibilityRecord record) {
        AccessibilityRecord clone = AccessibilityRecord.obtain();
        clone.init(record);
@@ -837,51 +829,25 @@
     }
 
     /**
-     * Returns a cached instance if such is available or a new one is
-     * instantiated.
+     * Instantiates a new record.
      *
-     * <p>In most situations object pooling is not beneficial. Create a new instance using the
+     * @deprecated Object pooling has been discontinued. Create a new instance using the
      * constructor {@link #AccessibilityRecord()} instead.
-     *
      * @return An instance.
      */
+    @Deprecated
     public static AccessibilityRecord obtain() {
-        synchronized (sPoolLock) {
-            if (sPool != null) {
-                AccessibilityRecord record = sPool;
-                sPool = sPool.mNext;
-                sPoolSize--;
-                record.mNext = null;
-                record.mIsInPool = false;
-                return record;
-            }
-            return new AccessibilityRecord();
-        }
+        return new AccessibilityRecord();
     }
 
     /**
-     * Return an instance back to be reused.
-     * <p>
-     * <strong>Note:</strong> You must not touch the object after calling this function.
+     * Would previously return an instance back to be reused.
      *
-     * <p>In most situations object pooling is not beneficial, and recycling is not necessary.
-     *
-     * @throws IllegalStateException If the record is already recycled.
+     * @deprecated Object pooling has been discontinued. Calling this function now will have
+     * no effect.
      */
-    public void recycle() {
-        if (mIsInPool) {
-            throw new IllegalStateException("Record already recycled!");
-        }
-        clear();
-        synchronized (sPoolLock) {
-            if (sPoolSize <= MAX_POOL_SIZE) {
-                mNext = sPool;
-                sPool = this;
-                mIsInPool = true;
-                sPoolSize++;
-            }
-        }
-    }
+    @Deprecated
+    public void recycle() { }
 
     /**
      * Initialize this record from another one.
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 1122056..bb13c1e 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -472,6 +472,24 @@
     public static final String DEVICE_CONFIG_AUGMENTED_SERVICE_REQUEST_TIMEOUT =
             "augmented_service_request_timeout";
 
+    /**
+     * Sets allowed list for the autofill compatibility mode.
+     *
+     * The list of packages is {@code ":"} colon delimited, and each entry has the name of the
+     * package and an optional list of url bar resource ids (the list is delimited by
+     * brackets&mdash{@code [} and {@code ]}&mdash and is also comma delimited).
+     *
+     * <p>For example, a list with 3 packages {@code p1}, {@code p2}, and {@code p3}, where
+     * package {@code p1} have one id ({@code url_bar}, {@code p2} has none, and {@code p3 }
+     * have 2 ids {@code url_foo} and {@code url_bas}) would be
+     * {@code p1[url_bar]:p2:p3[url_foo,url_bas]}
+     *
+     * @hide
+     */
+    @TestApi
+    public static final String DEVICE_CONFIG_AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES =
+            "compat_mode_allowed_packages";
+
     /** @hide */
     public static final int RESULT_OK = 0;
     /** @hide */
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 7566cea..3583cd4 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -86,6 +86,7 @@
 import android.view.autofill.AutofillManager;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.inputmethod.DirectBootAwareness;
 import com.android.internal.inputmethod.ImeTracing;
 import com.android.internal.inputmethod.InputBindResult;
 import com.android.internal.inputmethod.InputMethodDebug;
@@ -1234,6 +1235,26 @@
     }
 
     /**
+     * Returns the list of installed input methods for the specified user.
+     *
+     * @param userId user ID to query
+     * @param directBootAwareness {@code true} if caller want to query installed input methods list
+     * on user locked state.
+     * @return {@link List} of {@link InputMethodInfo}.
+     * @hide
+     */
+    @RequiresPermission(INTERACT_ACROSS_USERS_FULL)
+    @NonNull
+    public List<InputMethodInfo> getInputMethodListAsUser(@UserIdInt int userId,
+            @DirectBootAwareness int directBootAwareness) {
+        try {
+            return mService.getAwareLockedInputMethodList(userId, directBootAwareness);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Returns the list of enabled input methods.
      *
      * <p>On multi user environment, this API returns a result for the calling process user.</p>
@@ -2072,6 +2093,10 @@
                         + ", ic=" + ic + ", tba=" + tba + ", handler=" + icHandler);
             }
             view.onInputConnectionOpenedInternal(ic, tba, icHandler);
+            final ViewRootImpl viewRoot = view.getViewRootImpl();
+            if (viewRoot != null) {
+                viewRoot.getHandwritingInitiator().onInputConnectionCreated(view, tba);
+            }
         }
 
         return true;
diff --git a/core/java/android/view/inputmethod/TextAttribute.java b/core/java/android/view/inputmethod/TextAttribute.java
index bc76e78..57a555b9 100644
--- a/core/java/android/view/inputmethod/TextAttribute.java
+++ b/core/java/android/view/inputmethod/TextAttribute.java
@@ -36,7 +36,7 @@
     private final @NonNull List<String> mTextConversionSuggestions;
     private final @NonNull PersistableBundle mExtras;
 
-    private TextAttribute(TextAttributeBuilder builder) {
+    private TextAttribute(Builder builder) {
         mTextConversionSuggestions = builder.mTextConversionSuggestions;
         mExtras = builder.mExtras;
     }
@@ -48,7 +48,7 @@
 
     /**
      * Get the list of text conversion suggestions. More text conversion details in
-     * {@link TextAttributeBuilder#setTextConversionSuggestions(List)}.
+     * {@link Builder#setTextConversionSuggestions(List)}.
      *
      * @return List of text conversion suggestions. If the list is empty, it means that IME not set
      * this field or IME didn't have suggestions for applications.
@@ -59,7 +59,7 @@
 
     /**
      * Get the extras data. More extras data details in
-     * {@link TextAttributeBuilder#setExtras(PersistableBundle)}.
+     * {@link Builder#setExtras(PersistableBundle)}.
      *
      * @return Extras data. If the Bundle is empty, it means that IME not set this field or IME
      * didn't have extras data.
@@ -71,7 +71,7 @@
     /**
      * Builder for creating a {@link TextAttribute}.
      */
-    public static final class TextAttributeBuilder {
+    public static final class Builder {
         private List<String> mTextConversionSuggestions = new ArrayList<>();
         private PersistableBundle mExtras = new PersistableBundle();
 
@@ -87,7 +87,7 @@
          * @param textConversionSuggestions The list of text conversion suggestions.
          * @return This builder
          */
-        public @NonNull TextAttributeBuilder setTextConversionSuggestions(
+        public @NonNull Builder setTextConversionSuggestions(
                 @NonNull List<String> textConversionSuggestions) {
             mTextConversionSuggestions = Collections.unmodifiableList(textConversionSuggestions);
             return this;
@@ -101,7 +101,7 @@
          *
          * @return This builder.
          */
-        public @NonNull TextAttributeBuilder setExtras(@NonNull PersistableBundle extras) {
+        public @NonNull Builder setExtras(@NonNull PersistableBundle extras) {
             mExtras = extras;
             return this;
         }
diff --git a/core/java/android/view/selectiontoolbar/SelectionToolbarManager.java b/core/java/android/view/selectiontoolbar/SelectionToolbarManager.java
index 60688ea..ba45b85 100644
--- a/core/java/android/view/selectiontoolbar/SelectionToolbarManager.java
+++ b/core/java/android/view/selectiontoolbar/SelectionToolbarManager.java
@@ -20,6 +20,7 @@
 import android.annotation.SystemService;
 import android.content.Context;
 import android.os.RemoteException;
+import android.provider.DeviceConfig;
 
 import java.util.Objects;
 
@@ -40,6 +41,11 @@
      */
     public static final String LOG_TAG = "SelectionToolbar";
 
+    /**
+     * Whether system selection toolbar is enabled.
+     */
+    private static final String REMOTE_SELECTION_TOOLBAR_ENABLED =
+            "remote_selection_toolbar_enabled";
 
     @NonNull
     private final Context mContext;
@@ -86,4 +92,21 @@
             throw e.rethrowFromSystemServer();
         }
     }
+
+    private boolean isRemoteSelectionToolbarEnabled() {
+        return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SELECTION_TOOLBAR,
+                REMOTE_SELECTION_TOOLBAR_ENABLED, false);
+    }
+
+    /**
+     * Returns {@code true} if remote render selection toolbar enabled, otherwise
+     * returns {@code false}.
+     */
+    public static boolean isRemoteSelectionToolbarEnabled(Context context) {
+        SelectionToolbarManager manager = context.getSystemService(SelectionToolbarManager.class);
+        if (manager != null) {
+            return manager.isRemoteSelectionToolbarEnabled();
+        }
+        return false;
+    }
 }
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index a5f3feb..6d58ee2 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -301,6 +301,13 @@
     public static final int FLAG_USE_LIGHT_BACKGROUND_LAYOUT = 4;
 
     /**
+     * A ReadWriteHelper which has the same behavior as ReadWriteHelper.DEFAULT, but which is
+     * intentionally a different instance in order to trick Bundle reader so that it doesn't allow
+     * lazy initialization.
+     */
+    private static final Parcel.ReadWriteHelper ALTERNATIVE_DEFAULT = new Parcel.ReadWriteHelper();
+
+    /**
      * Used to restrict the views which can be inflated
      *
      * @see android.view.LayoutInflater.Filter#onLoadClass(java.lang.Class)
@@ -1856,7 +1863,18 @@
                     this.value = in.readTypedObject(Bitmap.CREATOR);
                     break;
                 case BUNDLE:
-                    this.value = in.readBundle();
+                    // Because we use Parcel.allowSquashing() when writing, and that affects
+                    //  how the contents of Bundles are written, we need to ensure the bundle is
+                    //  unparceled immediately, not lazily.  Setting a custom ReadWriteHelper
+                    //  just happens to have that effect on Bundle.readFromParcel().
+                    // TODO(b/212731590): build this state tracking into Bundle
+                    if (in.hasReadWriteHelper()) {
+                        this.value = in.readBundle();
+                    } else {
+                        in.setReadWriteHelper(ALTERNATIVE_DEFAULT);
+                        this.value = in.readBundle();
+                        in.setReadWriteHelper(null);
+                    }
                     break;
                 case INTENT:
                     this.value = in.readTypedObject(Intent.CREATOR);
diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java
index 862829b..dbf3570 100644
--- a/core/java/android/widget/Toast.java
+++ b/core/java/android/widget/Toast.java
@@ -74,6 +74,9 @@
  * <p>
  * Note that toasts being sent from the background are rate limited, so avoid sending such toasts
  * in quick succession.
+ * <p>
+ * Starting with Android 12 (API level 31), apps targeting Android 12 or newer will have
+ * their toasts limited to two lines.
  *
  * <div class="special reference">
  * <h3>Developer Guides</h3>
diff --git a/core/java/android/window/SplashScreen.java b/core/java/android/window/SplashScreen.java
index 090dbff..3f65f47 100644
--- a/core/java/android/window/SplashScreen.java
+++ b/core/java/android/window/SplashScreen.java
@@ -22,6 +22,7 @@
 import android.annotation.SuppressLint;
 import android.annotation.UiThread;
 import android.app.Activity;
+import android.app.ActivityOptions;
 import android.app.ActivityThread;
 import android.app.AppGlobals;
 import android.content.Context;
@@ -48,13 +49,13 @@
      */
     int SPLASH_SCREEN_STYLE_UNDEFINED = -1;
     /**
-     * Force splash screen to be empty.
-     * @hide
+     * Flag to be used with {@link ActivityOptions#setSplashScreenStyle}, to avoid showing the
+     * splash screen icon of the launched activity
      */
     int SPLASH_SCREEN_STYLE_EMPTY = 0;
     /**
-     * Force splash screen to show icon.
-     * @hide
+     * Flag to be used with {@link ActivityOptions#setSplashScreenStyle}, to show the splash screen
+     * icon of the launched activity.
      */
     int SPLASH_SCREEN_STYLE_ICON = 1;
 
diff --git a/core/java/android/window/TransitionInfo.java b/core/java/android/window/TransitionInfo.java
index 7208930..915c8fb 100644
--- a/core/java/android/window/TransitionInfo.java
+++ b/core/java/android/window/TransitionInfo.java
@@ -18,6 +18,7 @@
 
 import static android.app.ActivityOptions.ANIM_CLIP_REVEAL;
 import static android.app.ActivityOptions.ANIM_CUSTOM;
+import static android.app.ActivityOptions.ANIM_FROM_STYLE;
 import static android.app.ActivityOptions.ANIM_OPEN_CROSS_PROFILE_APPS;
 import static android.app.ActivityOptions.ANIM_SCALE_UP;
 import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_DOWN;
@@ -46,6 +47,7 @@
 import android.os.Parcelable;
 import android.view.Surface;
 import android.view.SurfaceControl;
+import android.view.WindowManager;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -581,6 +583,7 @@
         private String mPackageName;
         private final Rect mTransitionBounds = new Rect();
         private HardwareBuffer mThumbnail;
+        private int mAnimations;
 
         private AnimationOptions(int type) {
             mType = type;
@@ -594,6 +597,15 @@
             mPackageName = in.readString();
             mTransitionBounds.readFromParcel(in);
             mThumbnail = in.readTypedObject(HardwareBuffer.CREATOR);
+            mAnimations = in.readInt();
+        }
+
+        public static AnimationOptions makeAnimOptionsFromLayoutParameters(
+                WindowManager.LayoutParams lp) {
+            AnimationOptions options = new AnimationOptions(ANIM_FROM_STYLE);
+            options.mPackageName = lp.packageName;
+            options.mAnimations = lp.windowAnimations;
+            return options;
         }
 
         public static AnimationOptions makeCustomAnimOptions(String packageName, int enterResId,
@@ -662,6 +674,10 @@
             return mThumbnail;
         }
 
+        public int getAnimations() {
+            return mAnimations;
+        }
+
         @Override
         public void writeToParcel(Parcel dest, int flags) {
             dest.writeInt(mType);
@@ -671,6 +687,7 @@
             dest.writeString(mPackageName);
             mTransitionBounds.writeToParcel(dest, flags);
             dest.writeTypedObject(mThumbnail, flags);
+            dest.writeInt(mAnimations);
         }
 
         @NonNull
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index bc3c2f5..025f711 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -190,7 +190,7 @@
      * the handover intent.
      * TODO: investigate whether the privileged query is necessary to determine the availability.
      */
-    protected static final String EXTRA_IS_APP_PREDICTION_SERVICE_AVAILABLE =
+    public static final String EXTRA_IS_APP_PREDICTION_SERVICE_AVAILABLE =
             "com.android.internal.app.ChooserActivity.EXTRA_IS_APP_PREDICTION_SERVICE_AVAILABLE";
 
     /**
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index 1d13b73f..587876d 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -22,6 +22,7 @@
 import android.os.BatteryUsageStats;
 import android.os.BatteryUsageStatsQuery;
 import android.os.ParcelFileDescriptor;
+import android.os.WakeLockStats;
 import android.os.WorkSource;
 import android.os.connectivity.CellularBatteryStats;
 import android.os.connectivity.WifiActivityEnergyInfo;
@@ -157,6 +158,10 @@
     /** {@hide} */
     GpsBatteryStats getGpsBatteryStats();
 
+    /** {@hide} */
+    @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.BATTERY_STATS)")
+    WakeLockStats getWakeLockStats();
+
     HealthStatsParceler takeUidSnapshot(int uid);
     HealthStatsParceler[] takeUidSnapshots(in int[] uid);
 
diff --git a/telephony/java/com/android/internal/telephony/euicc/IResultCallback.aidl b/core/java/com/android/internal/compat/CompatibilityOverridesByPackageConfig.aidl
similarity index 76%
copy from telephony/java/com/android/internal/telephony/euicc/IResultCallback.aidl
copy to core/java/com/android/internal/compat/CompatibilityOverridesByPackageConfig.aidl
index 69f479c..eed4015 100644
--- a/telephony/java/com/android/internal/telephony/euicc/IResultCallback.aidl
+++ b/core/java/com/android/internal/compat/CompatibilityOverridesByPackageConfig.aidl
@@ -13,11 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.internal.telephony.euicc;
 
-import android.content.Intent;
+package com.android.internal.compat;
 
-/** @hide */
-oneway interface IResultCallback {
-    void onComplete(int resultCode, in Intent resultIntent);
-}
+parcelable CompatibilityOverridesByPackageConfig;
diff --git a/core/java/com/android/internal/compat/CompatibilityOverridesByPackageConfig.java b/core/java/com/android/internal/compat/CompatibilityOverridesByPackageConfig.java
new file mode 100644
index 0000000..8652bb6
--- /dev/null
+++ b/core/java/com/android/internal/compat/CompatibilityOverridesByPackageConfig.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.internal.compat;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Parcelable containing compat config overrides by application.
+ * @hide
+ */
+public final class CompatibilityOverridesByPackageConfig implements Parcelable {
+    public final Map<String, CompatibilityOverrideConfig> packageNameToOverrides;
+
+    public CompatibilityOverridesByPackageConfig(
+            Map<String, CompatibilityOverrideConfig> packageNameToOverrides) {
+        this.packageNameToOverrides = packageNameToOverrides;
+    }
+
+    private CompatibilityOverridesByPackageConfig(Parcel in) {
+        int keyCount = in.readInt();
+        packageNameToOverrides = new HashMap<>();
+        for (int i = 0; i < keyCount; i++) {
+            String key = in.readString();
+            packageNameToOverrides.put(key,
+                    CompatibilityOverrideConfig.CREATOR.createFromParcel(in));
+        }
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(packageNameToOverrides.size());
+        for (String key : packageNameToOverrides.keySet()) {
+            dest.writeString(key);
+            packageNameToOverrides.get(key).writeToParcel(dest, /* flags= */ 0);
+        }
+    }
+
+    public static final Parcelable.Creator<CompatibilityOverridesByPackageConfig> CREATOR =
+            new Parcelable.Creator<CompatibilityOverridesByPackageConfig>() {
+
+                @Override
+                public CompatibilityOverridesByPackageConfig createFromParcel(Parcel in) {
+                    return new CompatibilityOverridesByPackageConfig(in);
+                }
+
+                @Override
+                public CompatibilityOverridesByPackageConfig[] newArray(int size) {
+                    return new CompatibilityOverridesByPackageConfig[size];
+                }
+            };
+}
diff --git a/telephony/java/com/android/internal/telephony/euicc/IResultCallback.aidl b/core/java/com/android/internal/compat/CompatibilityOverridesToRemoveByPackageConfig.aidl
similarity index 76%
rename from telephony/java/com/android/internal/telephony/euicc/IResultCallback.aidl
rename to core/java/com/android/internal/compat/CompatibilityOverridesToRemoveByPackageConfig.aidl
index 69f479c..b9d0cef 100644
--- a/telephony/java/com/android/internal/telephony/euicc/IResultCallback.aidl
+++ b/core/java/com/android/internal/compat/CompatibilityOverridesToRemoveByPackageConfig.aidl
@@ -13,11 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.internal.telephony.euicc;
 
-import android.content.Intent;
+package com.android.internal.compat;
 
-/** @hide */
-oneway interface IResultCallback {
-    void onComplete(int resultCode, in Intent resultIntent);
-}
+parcelable CompatibilityOverridesToRemoveByPackageConfig;
diff --git a/core/java/com/android/internal/compat/CompatibilityOverridesToRemoveByPackageConfig.java b/core/java/com/android/internal/compat/CompatibilityOverridesToRemoveByPackageConfig.java
new file mode 100644
index 0000000..b408d64
--- /dev/null
+++ b/core/java/com/android/internal/compat/CompatibilityOverridesToRemoveByPackageConfig.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.compat;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Parcelable containing compat config change IDs for which to remove overrides by application.
+ *
+ * <p>This class is separate from CompatibilityOverridesByPackageConfig since we only need change
+ * IDs.
+ * @hide
+ */
+public final class CompatibilityOverridesToRemoveByPackageConfig implements Parcelable {
+    public final Map<String, CompatibilityOverridesToRemoveConfig> packageNameToOverridesToRemove;
+
+    public CompatibilityOverridesToRemoveByPackageConfig(
+            Map<String, CompatibilityOverridesToRemoveConfig> packageNameToOverridesToRemove) {
+        this.packageNameToOverridesToRemove = packageNameToOverridesToRemove;
+    }
+
+    private CompatibilityOverridesToRemoveByPackageConfig(Parcel in) {
+        int keyCount = in.readInt();
+        packageNameToOverridesToRemove = new HashMap<>();
+        for (int i = 0; i < keyCount; i++) {
+            String key = in.readString();
+            packageNameToOverridesToRemove.put(key,
+                    CompatibilityOverridesToRemoveConfig.CREATOR.createFromParcel(in));
+        }
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(packageNameToOverridesToRemove.size());
+        for (String key : packageNameToOverridesToRemove.keySet()) {
+            dest.writeString(key);
+            packageNameToOverridesToRemove.get(key).writeToParcel(dest, /* flags= */ 0);
+        }
+    }
+
+    public static final Parcelable.Creator<CompatibilityOverridesToRemoveByPackageConfig> CREATOR =
+            new Parcelable.Creator<CompatibilityOverridesToRemoveByPackageConfig>() {
+
+                @Override
+                public CompatibilityOverridesToRemoveByPackageConfig createFromParcel(Parcel in) {
+                    return new CompatibilityOverridesToRemoveByPackageConfig(in);
+                }
+
+                @Override
+                public CompatibilityOverridesToRemoveByPackageConfig[] newArray(int size) {
+                    return new CompatibilityOverridesToRemoveByPackageConfig[size];
+                }
+            };
+}
diff --git a/core/java/com/android/internal/compat/CompatibilityOverridesToRemoveConfig.java b/core/java/com/android/internal/compat/CompatibilityOverridesToRemoveConfig.java
index 642f79c..e85afef 100644
--- a/core/java/com/android/internal/compat/CompatibilityOverridesToRemoveConfig.java
+++ b/core/java/com/android/internal/compat/CompatibilityOverridesToRemoveConfig.java
@@ -26,6 +26,8 @@
 /**
  * Parcelable containing compat config change IDs for which to remove overrides for a given
  * application.
+ *
+ * <p>This class is separate from CompatibilityOverrideConfig since we only need change IDs.
  * @hide
  */
 public final class CompatibilityOverridesToRemoveConfig implements Parcelable {
diff --git a/core/java/com/android/internal/compat/IPlatformCompat.aidl b/core/java/com/android/internal/compat/IPlatformCompat.aidl
index 418d16e..8847a49 100644
--- a/core/java/com/android/internal/compat/IPlatformCompat.aidl
+++ b/core/java/com/android/internal/compat/IPlatformCompat.aidl
@@ -22,6 +22,8 @@
 
 parcelable CompatibilityChangeConfig;
 parcelable CompatibilityOverrideConfig;
+parcelable CompatibilityOverridesByPackageConfig;
+parcelable CompatibilityOverridesToRemoveByPackageConfig;
 parcelable CompatibilityOverridesToRemoveConfig;
 parcelable CompatibilityChangeInfo;
 /**
@@ -152,6 +154,26 @@
     void setOverrides(in CompatibilityChangeConfig overrides, in String packageName);
 
     /**
+     * Adds overrides to compatibility changes on release builds for multiple apps.
+     *
+     * <p>The caller to this API needs to hold
+     * {@code android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD} and all change ids
+     * in {@code overridesByPackage} need to annotated with {@link
+     * android.compat.annotation.Overridable}.
+     *
+     * A release build in this definition means that {@link android.os.Build#IS_DEBUGGABLE} needs to
+     * be {@code false}.
+     *
+     * <p>Note that this does not kill the app, and therefore overrides read from the app process
+     * will not be updated. Overrides read from the system process do take effect.
+     *
+     * @param overridesByPackage parcelable containing the compat change overrides to be applied
+     *                           on specific apps by their package name
+     * @throws SecurityException if overriding changes is not permitted
+     */
+    void putAllOverridesOnReleaseBuilds(in CompatibilityOverridesByPackageConfig overridesByPackage);
+
+    /**
      * Adds overrides to compatibility changes on release builds.
      *
      * <p>The caller to this API needs to hold
@@ -206,6 +228,26 @@
     boolean clearOverrideForTest(long changeId, String packageName);
 
     /**
+     * Restores the default behaviour for compatibility changes on release builds for multiple apps.
+     *
+     * <p>The caller to this API needs to hold
+     * {@code android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD} and all change ids
+     * in {@code overridesToRemoveByPackage} need to annotated with {@link
+     * android.compat.annotation.Overridable}.
+     *
+     * A release build in this definition means that {@link android.os.Build#IS_DEBUGGABLE} needs to
+     * be {@code false}.
+     *
+     * <p>Note that this does not kill the app, and therefore overrides read from the app process
+     * will not be updated. Overrides read from the system process do take effect.
+     *
+     * @param overridesToRemoveByPackage parcelable containing the compat change overrides to be
+     *                                   removed for specific apps by their package name
+     * @throws SecurityException if overriding changes is not permitted
+     */
+    void removeAllOverridesOnReleaseBuilds(in CompatibilityOverridesToRemoveByPackageConfig overridesToRemoveByPackage);
+
+    /**
      * Restores the default behaviour for compatibility changes on release builds.
      *
      * <p>The caller to this API needs to hold
diff --git a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
index 6a6f60e..f904610 100644
--- a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
+++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
@@ -157,6 +157,12 @@
      */
     public static final String PROPERTY_LOCATION_INDICATORS_ENABLED = "location_indicators_enabled";
 
+    /**
+     * Whether to show old location indicator on all location accesses.
+     */
+    public static final String PROPERTY_LOCATION_INDICATORS_SMALL_ENABLED =
+            "location_indicators_small_enabled";
+
     // Flags related to Assistant
 
     /**
diff --git a/core/java/com/android/internal/inputmethod/DirectBootAwareness.java b/core/java/com/android/internal/inputmethod/DirectBootAwareness.java
new file mode 100644
index 0000000..51f914f
--- /dev/null
+++ b/core/java/com/android/internal/inputmethod/DirectBootAwareness.java
@@ -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.internal.inputmethod;
+
+
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+
+/**
+ * Specifies the decided filtering mode regarding IMEs' DirectBoot awareness when querying IMEs.
+ */
+@Retention(SOURCE)
+@IntDef({DirectBootAwareness.AUTO, DirectBootAwareness.ANY})
+public @interface DirectBootAwareness {
+    /**
+     * The same semantics as {@link android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AUTO}, that
+     * is, if the user to be queried is still locked, then only DirectBoot-aware IMEs will be
+     * matched.  If the user to be queried is already unlocked, then IMEs will not be filtered out
+     * based on their DirectBoot awareness.
+     */
+    int AUTO = 0;
+    /**
+     * The same semantics as specifying <strong>both</strong>
+     * {@link android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE} and
+     * {@link android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE}, that is, IME will never
+     * be filtered out based on their DirectBoot awareness, no matter whether the user to be queried
+     * is still locked or already unlocked.
+     */
+    int ANY = 1;
+}
diff --git a/core/java/com/android/internal/inputmethod/RemoteInputConnectionImpl.java b/core/java/com/android/internal/inputmethod/RemoteInputConnectionImpl.java
index 662ed6b..0470444 100644
--- a/core/java/com/android/internal/inputmethod/RemoteInputConnectionImpl.java
+++ b/core/java/com/android/internal/inputmethod/RemoteInputConnectionImpl.java
@@ -36,6 +36,7 @@
 import android.util.proto.ProtoOutputStream;
 import android.view.KeyEvent;
 import android.view.View;
+import android.view.ViewRootImpl;
 import android.view.inputmethod.CompletionInfo;
 import android.view.inputmethod.CorrectionInfo;
 import android.view.inputmethod.DumpableInputConnection;
@@ -350,8 +351,19 @@
                     }
                     if (handler.getLooper().isCurrentThread()) {
                         servedView.onInputConnectionClosedInternal();
+                        final ViewRootImpl viewRoot = servedView.getViewRootImpl();
+                        if (viewRoot != null) {
+                            viewRoot.getHandwritingInitiator().onInputConnectionClosed(servedView);
+                        }
                     } else {
                         handler.post(servedView::onInputConnectionClosedInternal);
+                        handler.post(() -> {
+                            final ViewRootImpl viewRoot = servedView.getViewRootImpl();
+                            if (viewRoot != null) {
+                                viewRoot.getHandwritingInitiator()
+                                        .onInputConnectionClosed(servedView);
+                            }
+                        });
                     }
                 }
             }
diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java
index ea38db3..0d4ad38 100644
--- a/core/java/com/android/internal/jank/InteractionJankMonitor.java
+++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java
@@ -42,6 +42,8 @@
 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_UNLOCK_ANIMATION;
 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__NOTIFICATION_SHADE_SWIPE;
 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__PIP_TRANSITION;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SCREEN_OFF;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SCREEN_OFF_SHOW_AOD;
 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SETTINGS_PAGE_SCROLL;
 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_APP_LAUNCH;
 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_APP_LAUNCH_FROM_HISTORY_BUTTON;
@@ -177,6 +179,8 @@
     public static final int CUJ_USER_SWITCH = 37;
     public static final int CUJ_SPLASHSCREEN_AVD = 38;
     public static final int CUJ_SPLASHSCREEN_EXIT_ANIM = 39;
+    public static final int CUJ_SCREEN_OFF = 40;
+    public static final int CUJ_SCREEN_OFF_SHOW_AOD = 41;
 
     private static final int NO_STATSD_LOGGING = -1;
 
@@ -225,6 +229,8 @@
             UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__USER_SWITCH,
             UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SPLASHSCREEN_AVD,
             UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SPLASHSCREEN_EXIT_ANIM,
+            UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SCREEN_OFF,
+            UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SCREEN_OFF_SHOW_AOD,
     };
 
     private static volatile InteractionJankMonitor sInstance;
@@ -285,6 +291,8 @@
             CUJ_USER_SWITCH,
             CUJ_SPLASHSCREEN_AVD,
             CUJ_SPLASHSCREEN_EXIT_ANIM,
+            CUJ_SCREEN_OFF,
+            CUJ_SCREEN_OFF_SHOW_AOD,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface CujType {
@@ -423,6 +431,16 @@
     }
 
     /**
+     * @param cujType cuj type
+     * @return true if the cuj is under instrumenting, false otherwise.
+     */
+    public boolean isInstrumenting(@CujType int cujType) {
+        synchronized (mLock) {
+            return mRunningTrackers.contains(cujType);
+        }
+    }
+
+    /**
      * Begins a trace session.
      *
      * @param v an attached view.
@@ -690,6 +708,10 @@
                 return "SPLASHSCREEN_AVD";
             case CUJ_SPLASHSCREEN_EXIT_ANIM:
                 return "SPLASHSCREEN_EXIT_ANIM";
+            case CUJ_SCREEN_OFF:
+                return "SCREEN_OFF";
+            case CUJ_SCREEN_OFF_SHOW_AOD:
+                return "SCREEN_OFF_SHOW_AOD";
         }
         return "UNKNOWN";
     }
diff --git a/core/java/com/android/internal/net/NetworkUtilsInternal.java b/core/java/com/android/internal/net/NetworkUtilsInternal.java
index 052959a..1b6cb29 100644
--- a/core/java/com/android/internal/net/NetworkUtilsInternal.java
+++ b/core/java/com/android/internal/net/NetworkUtilsInternal.java
@@ -74,35 +74,4 @@
 
         return true;
     }
-
-    /**
-     * Safely multiple a value by a rational.
-     * <p>
-     * Internally it uses integer-based math whenever possible, but switches
-     * over to double-based math if values would overflow.
-     * @hide
-     */
-    public static long multiplySafeByRational(long value, long num, long den) {
-        if (den == 0) {
-            throw new ArithmeticException("Invalid Denominator");
-        }
-        long x = value;
-        long y = num;
-
-        // Logic shamelessly borrowed from Math.multiplyExact()
-        long r = x * y;
-        long ax = Math.abs(x);
-        long ay = Math.abs(y);
-        if (((ax | ay) >>> 31 != 0)) {
-            // Some bits greater than 2^31 that might cause overflow
-            // Check the result using the divide operator
-            // and check for the special case of Long.MIN_VALUE * -1
-            if (((y != 0) && (r / y != x))
-                    || (x == Long.MIN_VALUE && y == -1)) {
-                // Use double math to avoid overflowing
-                return (long) (((double) num / den) * value);
-            }
-        }
-        return r / den;
-    }
 }
diff --git a/core/java/com/android/internal/net/VpnProfile.java b/core/java/com/android/internal/net/VpnProfile.java
index d0a8c32..519faa8 100644
--- a/core/java/com/android/internal/net/VpnProfile.java
+++ b/core/java/com/android/internal/net/VpnProfile.java
@@ -143,17 +143,24 @@
     public boolean areAuthParamsInline = false;                  // 23
     public final boolean isRestrictedToTestNetworks;             // 24
 
+    public final boolean excludeLocalRoutes;                     // 25
+
     // Helper fields.
     @UnsupportedAppUsage
     public transient boolean saveLogin = false;
 
     public VpnProfile(String key) {
-        this(key, false);
+        this(key, false, false);
     }
 
     public VpnProfile(String key, boolean isRestrictedToTestNetworks) {
+        this(key, isRestrictedToTestNetworks, false);
+    }
+
+    public VpnProfile(String key, boolean isRestrictedToTestNetworks, boolean excludeLocalRoutes) {
         this.key = key;
         this.isRestrictedToTestNetworks = isRestrictedToTestNetworks;
+        this.excludeLocalRoutes = excludeLocalRoutes;
     }
 
     @UnsupportedAppUsage
@@ -183,6 +190,7 @@
         maxMtu = in.readInt();
         areAuthParamsInline = in.readBoolean();
         isRestrictedToTestNetworks = in.readBoolean();
+        excludeLocalRoutes = in.readBoolean();
     }
 
     /**
@@ -230,6 +238,7 @@
         out.writeInt(maxMtu);
         out.writeBoolean(areAuthParamsInline);
         out.writeBoolean(isRestrictedToTestNetworks);
+        out.writeBoolean(excludeLocalRoutes);
     }
 
     /**
@@ -249,8 +258,9 @@
             // 14-19: Standard profile, with option for serverCert, proxy
             // 24: Standard profile with serverCert, proxy and platform-VPN parameters
             // 25: Standard profile with platform-VPN parameters and isRestrictedToTestNetworks
+            // 26: Standard profile with platform-VPN parameters and excludeLocalRoutes
             if ((values.length < 14 || values.length > 19)
-                    && values.length != 24 && values.length != 25) {
+                    && values.length != 24 && values.length != 25 && values.length != 26) {
                 return null;
             }
 
@@ -261,7 +271,15 @@
                 isRestrictedToTestNetworks = false;
             }
 
-            VpnProfile profile = new VpnProfile(key, isRestrictedToTestNetworks);
+            final boolean excludeLocalRoutes;
+            if (values.length >= 26) {
+                excludeLocalRoutes = Boolean.parseBoolean(values[25]);
+            } else {
+                excludeLocalRoutes = false;
+            }
+
+            VpnProfile profile = new VpnProfile(key, isRestrictedToTestNetworks,
+                    excludeLocalRoutes);
             profile.name = values[0];
             profile.type = Integer.parseInt(values[1]);
             if (profile.type < 0 || profile.type > TYPE_MAX) {
@@ -371,6 +389,8 @@
         builder.append(VALUE_DELIMITER).append(areAuthParamsInline);
         builder.append(VALUE_DELIMITER).append(isRestrictedToTestNetworks);
 
+        builder.append(VALUE_DELIMITER).append(excludeLocalRoutes);
+
         return builder.toString().getBytes(StandardCharsets.UTF_8);
     }
 
@@ -451,7 +471,7 @@
             key, type, server, username, password, dnsServers, searchDomains, routes, mppe,
             l2tpSecret, ipsecIdentifier, ipsecSecret, ipsecUserCert, ipsecCaCert, ipsecServerCert,
             proxy, mAllowedAlgorithms, isBypassable, isMetered, maxMtu, areAuthParamsInline,
-            isRestrictedToTestNetworks);
+            isRestrictedToTestNetworks, excludeLocalRoutes);
     }
 
     /** Checks VPN profiles for interior equality. */
@@ -484,7 +504,8 @@
                 && isMetered == other.isMetered
                 && maxMtu == other.maxMtu
                 && areAuthParamsInline == other.areAuthParamsInline
-                && isRestrictedToTestNetworks == other.isRestrictedToTestNetworks;
+                && isRestrictedToTestNetworks == other.isRestrictedToTestNetworks
+                && excludeLocalRoutes == other.excludeLocalRoutes;
     }
 
     @NonNull
diff --git a/core/java/com/android/internal/os/BatteryStatsHistory.java b/core/java/com/android/internal/os/BatteryStatsHistory.java
index 879e0a8..b0fce8f 100644
--- a/core/java/com/android/internal/os/BatteryStatsHistory.java
+++ b/core/java/com/android/internal/os/BatteryStatsHistory.java
@@ -160,6 +160,11 @@
         mHistoryDir = null;
         mHistoryBuffer = historyBuffer;
     }
+
+    public File getHistoryDirectory() {
+        return mHistoryDir;
+    }
+
     /**
      * Set the active file that mHistoryBuffer is backed up into.
      *
@@ -375,12 +380,26 @@
     }
 
     /**
-     * Read all history files and serialize into a big Parcel. This is to send history files to
-     * Settings app since Settings app can not access /data/system directory.
-     * Checkin file also call this method.
+     * Read all history files and serialize into a big Parcel.
+     * Checkin file calls this method.
+     *
      * @param out the output parcel
      */
     public void writeToParcel(Parcel out) {
+        writeToParcel(out, false /* useBlobs */);
+    }
+
+    /**
+     * This is for Settings app, when Settings app receives big history parcel, it call
+     * this method to parse it into list of parcels.
+     * @param out the output parcel
+     */
+    public void writeToBatteryUsageStatsParcel(Parcel out) {
+        out.writeBlob(mHistoryBuffer.marshall());
+        writeToParcel(out, true /* useBlobs */);
+    }
+
+    private void writeToParcel(Parcel out, boolean useBlobs) {
         final long start = SystemClock.uptimeMillis();
         out.writeInt(mFileNumbers.size() - 1);
         for(int i = 0;  i < mFileNumbers.size() - 1; i++) {
@@ -391,7 +410,12 @@
             } catch(Exception e) {
                 Slog.e(TAG, "Error reading file "+ file.getBaseFile().getPath(), e);
             }
-            out.writeByteArray(raw);
+            if (useBlobs) {
+                out.writeBlob(raw);
+            } else {
+                // Avoiding blobs in the check-in file for compatibility
+                out.writeByteArray(raw);
+            }
         }
         if (DEBUG) {
             Slog.d(TAG, "writeToParcel duration ms:" + (SystemClock.uptimeMillis() - start));
@@ -399,18 +423,36 @@
     }
 
     /**
-     * This is for Settings app, when Settings app receives big history parcel, it call
-     * this method to parse it into list of parcels.
-     * Checkin file also call this method.
+     * Reads a BatteryStatsHistory from a parcel written with
+     * the {@link #writeToBatteryUsageStatsParcel} method.
+     */
+    public static BatteryStatsHistory createFromBatteryUsageStatsParcel(Parcel in) {
+        final byte[] historyBlob = in.readBlob();
+
+        Parcel historyBuffer = Parcel.obtain();
+        historyBuffer.unmarshall(historyBlob, 0, historyBlob.length);
+
+        BatteryStatsHistory history = new BatteryStatsHistory(historyBuffer);
+        history.readFromParcel(in, true /* useBlobs */);
+        return history;
+    }
+
+    /**
+     * This is for the check-in file, which has all history files embedded.
+     *
      * @param in the input parcel.
      */
     public void readFromParcel(Parcel in) {
+        readFromParcel(in, false /* useBlobs */);
+    }
+
+    private void readFromParcel(Parcel in, boolean useBlobs) {
         final long start = SystemClock.uptimeMillis();
         mHistoryParcels = new ArrayList<>();
         final int count = in.readInt();
         for(int i = 0; i < count; i++) {
-            byte[] temp = in.createByteArray();
-            if (temp.length == 0) {
+            byte[] temp = useBlobs ? in.readBlob() : in.createByteArray();
+            if (temp == null || temp.length == 0) {
                 continue;
             }
             Parcel p = Parcel.obtain();
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 209c64a..21f719c 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -60,6 +60,7 @@
 import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.UserHandle;
+import android.os.WakeLockStats;
 import android.os.WorkSource;
 import android.os.WorkSource.WorkChain;
 import android.os.connectivity.CellularBatteryStats;
@@ -1143,6 +1144,37 @@
         return mKernelWakelockStats;
     }
 
+    @Override
+    public WakeLockStats getWakeLockStats() {
+        final long realtimeMs = mClock.elapsedRealtime();
+        final long realtimeUs = realtimeMs * 1000;
+        List<WakeLockStats.WakeLock> uidWakeLockStats = new ArrayList<>();
+        for (int i = mUidStats.size() - 1; i >= 0; i--) {
+            final Uid uid = mUidStats.valueAt(i);
+            final ArrayMap<String, ? extends BatteryStats.Uid.Wakelock> wakelockStats =
+                    uid.mWakelockStats.getMap();
+            for (int j = wakelockStats.size() - 1; j >= 0; j--) {
+                final String name = wakelockStats.keyAt(j);
+                final Uid.Wakelock wakelock = (Uid.Wakelock) wakelockStats.valueAt(j);
+                final DualTimer timer = wakelock.mTimerPartial;
+                if (timer != null) {
+                    final long totalTimeLockHeldMs =
+                            timer.getTotalTimeLocked(realtimeUs, STATS_SINCE_CHARGED) / 1000;
+                    if (totalTimeLockHeldMs != 0) {
+                        uidWakeLockStats.add(
+                                new WakeLockStats.WakeLock(uid.getUid(), name,
+                                        timer.getCountLocked(STATS_SINCE_CHARGED),
+                                        totalTimeLockHeldMs,
+                                        timer.isRunningLocked()
+                                                ? timer.getCurrentDurationMsLocked(realtimeMs)
+                                                : 0));
+                    }
+                }
+            }
+        }
+        return new WakeLockStats(uidWakeLockStats);
+    }
+
     String mLastWakeupReason = null;
     long mLastWakeupUptimeMs = 0;
     private final HashMap<String, SamplingTimer> mWakeupReasonStats = new HashMap<>();
diff --git a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
index 88425be..69b7b4e 100644
--- a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
+++ b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
@@ -21,13 +21,16 @@
 import android.os.BatteryStats;
 import android.os.BatteryUsageStats;
 import android.os.BatteryUsageStatsQuery;
+import android.os.Parcel;
 import android.os.SystemClock;
 import android.os.UidBatteryConsumer;
 import android.util.Log;
 import android.util.SparseArray;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 
+import java.io.File;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
@@ -133,9 +136,12 @@
      */
     @VisibleForTesting
     public BatteryUsageStats getBatteryUsageStats(BatteryUsageStatsQuery query) {
-        return getBatteryUsageStats(query, currentTimeMillis());
+        synchronized (mStats) {
+            return getBatteryUsageStats(query, currentTimeMillis());
+        }
     }
 
+    @GuardedBy("mStats")
     private BatteryUsageStats getBatteryUsageStats(BatteryUsageStatsQuery query,
             long currentTimeMs) {
         if (query.getToTimestamp() == 0) {
@@ -145,6 +151,7 @@
         }
     }
 
+    @GuardedBy("mStats")
     private BatteryUsageStats getCurrentBatteryUsageStats(BatteryUsageStatsQuery query,
             long currentTimeMs) {
         final long realtimeUs = elapsedRealtime() * 1000;
@@ -189,7 +196,18 @@
             }
 
             BatteryStatsImpl batteryStatsImpl = (BatteryStatsImpl) mStats;
-            batteryUsageStatsBuilder.setBatteryHistory(batteryStatsImpl.mHistoryBuffer);
+
+            // Make a copy of battery history to avoid concurrent modification.
+            Parcel historyBuffer = Parcel.obtain();
+            historyBuffer.appendFrom(batteryStatsImpl.mHistoryBuffer, 0,
+                    batteryStatsImpl.mHistoryBuffer.dataSize());
+
+            final File systemDir =
+                    batteryStatsImpl.mBatteryStatsHistory.getHistoryDirectory().getParentFile();
+            final BatteryStatsHistory batteryStatsHistory =
+                    new BatteryStatsHistory(batteryStatsImpl, systemDir, historyBuffer);
+
+            batteryUsageStatsBuilder.setBatteryHistory(batteryStatsHistory);
         }
 
         return batteryUsageStatsBuilder.build();
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 6541b14..ba7a0ef 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -121,7 +121,7 @@
 import com.android.internal.widget.ActionBarContextView;
 import com.android.internal.widget.BackgroundFallback;
 import com.android.internal.widget.DecorCaptionView;
-import com.android.internal.widget.FloatingToolbar;
+import com.android.internal.widget.floatingtoolbar.FloatingToolbar;
 
 import java.util.List;
 import java.util.function.Consumer;
diff --git a/core/java/com/android/internal/policy/IKeyguardService.aidl b/core/java/com/android/internal/policy/IKeyguardService.aidl
index 76aa7a0..36b7ee5 100644
--- a/core/java/com/android/internal/policy/IKeyguardService.aidl
+++ b/core/java/com/android/internal/policy/IKeyguardService.aidl
@@ -15,6 +15,7 @@
  */
 package com.android.internal.policy;
 
+import android.content.Intent;
 import com.android.internal.policy.IKeyguardDrawnCallback;
 import com.android.internal.policy.IKeyguardDismissCallback;
 import com.android.internal.policy.IKeyguardStateCallback;
@@ -113,7 +114,20 @@
 
     /**
      * Notifies the Keyguard that the power key was pressed while locked and launched Home rather
-     * than putting the device to sleep or waking up.
+     * than putting the device to sleep or waking up. Note that it's called only if the device is
+     * interactive.
      */
     void onShortPowerPressedGoHome();
+
+    /**
+     * Notifies the Keyguard that it needs to bring up a bouncer and then launch the intent as soon
+     * as user unlocks the watch.
+     */
+    void dismissKeyguardToLaunch(in Intent intentToLaunch);
+
+    /**
+     * Notifies the Keyguard that a key was pressed while locked so the Keyguard can handle it.
+     * Note that it's called only if the device is interactive.
+     */
+    void onSystemKeyPressed(int keycode);
 }
diff --git a/core/java/com/android/internal/policy/TransitionAnimation.java b/core/java/com/android/internal/policy/TransitionAnimation.java
index d3224b1..faea7706e 100644
--- a/core/java/com/android/internal/policy/TransitionAnimation.java
+++ b/core/java/com/android/internal/policy/TransitionAnimation.java
@@ -260,25 +260,39 @@
         return null;
     }
 
-    /** Load animation by attribute Id from android package. */
+    /** Load animation by attribute Id from a specific AnimationStyle resource. */
     @Nullable
-    public Animation loadDefaultAnimationAttr(int animAttr) {
+    public Animation loadAnimationAttr(String packageName, int animStyleResId, int animAttr,
+            boolean translucent) {
+        if (animStyleResId == 0) {
+            return null;
+        }
         int resId = Resources.ID_NULL;
         Context context = mContext;
         if (animAttr >= 0) {
-            AttributeCache.Entry ent = getCachedAnimations(DEFAULT_PACKAGE,
-                    mDefaultWindowAnimationStyleResId);
+            packageName = packageName != null ? packageName : DEFAULT_PACKAGE;
+            AttributeCache.Entry ent = getCachedAnimations(packageName, animStyleResId);
             if (ent != null) {
                 context = ent.context;
                 resId = ent.array.getResourceId(animAttr, 0);
             }
         }
+        if (translucent) {
+            resId = updateToTranslucentAnimIfNeeded(resId);
+        }
         if (ResourceId.isValid(resId)) {
             return loadAnimationSafely(context, resId, mTag);
         }
         return null;
     }
 
+    /** Load animation by attribute Id from android package. */
+    @Nullable
+    public Animation loadDefaultAnimationAttr(int animAttr) {
+        return loadAnimationAttr(DEFAULT_PACKAGE, mDefaultWindowAnimationStyleResId, animAttr,
+                false /* translucent */);
+    }
+
     @Nullable
     private AttributeCache.Entry getCachedAnimations(LayoutParams lp) {
         if (mDebug) {
@@ -1024,6 +1038,16 @@
         return anim;
     }
 
+    private static int updateToTranslucentAnimIfNeeded(int anim) {
+        if (anim == R.anim.activity_open_enter) {
+            return R.anim.activity_translucent_open_enter;
+        }
+        if (anim == R.anim.activity_close_exit) {
+            return R.anim.activity_translucent_close_exit;
+        }
+        return anim;
+    }
+
     private static @TransitionOldType int getTransitCompatType(@TransitionType int transit,
             int wallpaperTransit) {
         if (wallpaperTransit == WALLPAPER_TRANSITION_INTRA_OPEN) {
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index 1db7426..3c6b7ff 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -162,4 +162,20 @@
 
     void requestAddTile(in ComponentName componentName, in CharSequence label, in Icon icon, int userId, in IAddTileResultCallback callback);
     void cancelRequestAddTile(in String packageName);
+
+    /**
+    * Overrides the navigation bar mode.
+    *
+    * @param navBarModeOverride the mode of the navigation bar override to be set.
+    *
+    * @hide
+    */
+    void setNavBarModeOverride(int navBarModeOverride);
+
+    /**
+    * Gets the navigation bar mode override.
+    *
+    * @hide
+    */
+    int getNavBarModeOverride();
 }
diff --git a/core/java/com/android/internal/util/LatencyTracker.java b/core/java/com/android/internal/util/LatencyTracker.java
index e95ba88..1cd758c 100644
--- a/core/java/com/android/internal/util/LatencyTracker.java
+++ b/core/java/com/android/internal/util/LatencyTracker.java
@@ -127,6 +127,11 @@
      */
     public static final int ACTION_SWITCH_DISPLAY_UNFOLD = 13;
 
+    /**
+     * Time it takes for a UDFPS sensor to appear ready after it is touched.
+     */
+    public static final int ACTION_UDFPS_ILLUMINATE = 14;
+
     private static final int[] ACTIONS_ALL = {
         ACTION_EXPAND_PANEL,
         ACTION_TOGGLE_RECENTS,
@@ -141,7 +146,8 @@
         ACTION_ROTATE_SCREEN_CAMERA_CHECK,
         ACTION_LOCKSCREEN_UNLOCK,
         ACTION_USER_SWITCH,
-        ACTION_SWITCH_DISPLAY_UNFOLD
+        ACTION_SWITCH_DISPLAY_UNFOLD,
+        ACTION_UDFPS_ILLUMINATE
     };
 
     /** @hide */
@@ -159,7 +165,8 @@
         ACTION_ROTATE_SCREEN_CAMERA_CHECK,
         ACTION_LOCKSCREEN_UNLOCK,
         ACTION_USER_SWITCH,
-        ACTION_SWITCH_DISPLAY_UNFOLD
+        ACTION_SWITCH_DISPLAY_UNFOLD,
+        ACTION_UDFPS_ILLUMINATE
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface Action {
@@ -179,7 +186,8 @@
             FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_ROTATE_SCREEN_CAMERA_CHECK,
             FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_LOCKSCREEN_UNLOCK,
             FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_USER_SWITCH,
-            FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_SWITCH_DISPLAY_UNFOLD
+            FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_SWITCH_DISPLAY_UNFOLD,
+            FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_UDFPS_ILLUMINATE
     };
 
     private static LatencyTracker sLatencyTracker;
@@ -267,6 +275,8 @@
                 return "ACTION_USER_SWITCH";
             case 14:
                 return "ACTION_SWITCH_DISPLAY_UNFOLD";
+            case 15:
+                return "ACTION_UDFPS_ILLUMINATE";
             default:
                 throw new IllegalArgumentException("Invalid action");
         }
diff --git a/core/java/com/android/internal/view/FloatingActionMode.java b/core/java/com/android/internal/view/FloatingActionMode.java
index 36913b7..06e69f2 100644
--- a/core/java/com/android/internal/view/FloatingActionMode.java
+++ b/core/java/com/android/internal/view/FloatingActionMode.java
@@ -33,7 +33,7 @@
 
 import com.android.internal.R;
 import com.android.internal.view.menu.MenuBuilder;
-import com.android.internal.widget.FloatingToolbar;
+import com.android.internal.widget.floatingtoolbar.FloatingToolbar;
 
 import java.util.Arrays;
 import java.util.Objects;
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index 350ec33..2dc7c42c 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -35,6 +35,7 @@
 
     // TODO: Use ParceledListSlice instead
     List<InputMethodInfo> getInputMethodList(int userId);
+    List<InputMethodInfo> getAwareLockedInputMethodList(int userId, int directBootAwareness);
     // TODO: Use ParceledListSlice instead
     List<InputMethodInfo> getEnabledInputMethodList(int userId);
     List<InputMethodSubtype> getEnabledInputMethodSubtypeList(in String imiId,
diff --git a/core/java/com/android/internal/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/floatingtoolbar/FloatingToolbar.java
similarity index 88%
rename from core/java/com/android/internal/widget/FloatingToolbar.java
rename to core/java/com/android/internal/widget/floatingtoolbar/FloatingToolbar.java
index a0bf9b5..e75f372 100644
--- a/core/java/com/android/internal/widget/FloatingToolbar.java
+++ b/core/java/com/android/internal/widget/floatingtoolbar/FloatingToolbar.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.internal.widget;
+package com.android.internal.widget.floatingtoolbar;
 
 import android.annotation.Nullable;
 import android.graphics.Rect;
@@ -50,14 +50,10 @@
     private final FloatingToolbarPopup mPopup;
 
     private final Rect mContentRect = new Rect();
-    private final Rect mPreviousContentRect = new Rect();
 
     private Menu mMenu;
     private MenuItem.OnMenuItemClickListener mMenuItemClickListener = NO_OP_MENUITEM_CLICK_LISTENER;
 
-    private int mSuggestedWidth;
-    private boolean mWidthChanged = true;
-
     private final OnLayoutChangeListener mOrientationChangeHandler = new OnLayoutChangeListener() {
 
         private final Rect mNewRect = new Rect();
@@ -71,7 +67,7 @@
             mNewRect.set(newLeft, newRight, newTop, newBottom);
             mOldRect.set(oldLeft, oldRight, oldTop, oldBottom);
             if (mPopup.isShowing() && !mNewRect.equals(mOldRect)) {
-                mWidthChanged = true;
+                mPopup.setWidthChanged(true);
                 updateLayout();
             }
         }
@@ -114,7 +110,7 @@
         // TODO(b/65172902): Pass context in constructor when DecorView (and other callers)
         // supports multi-display.
         mWindow = Objects.requireNonNull(window);
-        mPopup = new FloatingToolbarPopup(window.getContext(), window.getDecorView());
+        mPopup = FloatingToolbarPopup.createInstance(window.getContext(), window.getDecorView());
     }
 
     /**
@@ -159,11 +155,7 @@
      * toolbar.
      */
     public FloatingToolbar setSuggestedWidth(int suggestedWidth) {
-        // Check if there's been a substantial width spec change.
-        int difference = Math.abs(suggestedWidth - mSuggestedWidth);
-        mWidthChanged = difference > (mSuggestedWidth * 0.2);
-
-        mSuggestedWidth = suggestedWidth;
+        mPopup.setSuggestedWidth(suggestedWidth);
         return this;
     }
 
@@ -232,19 +224,7 @@
     private void doShow() {
         List<MenuItem> menuItems = getVisibleAndEnabledMenuItems(mMenu);
         menuItems.sort(mMenuItemComparator);
-        if (mPopup.isLayoutRequired(menuItems) || mWidthChanged) {
-            mPopup.dismiss();
-            mPopup.layoutMenuItems(menuItems, mMenuItemClickListener, mSuggestedWidth);
-        } else {
-            mPopup.updateMenuItems(menuItems, mMenuItemClickListener);
-        }
-        if (!mPopup.isShowing()) {
-            mPopup.show(mContentRect);
-        } else if (!mPreviousContentRect.equals(mContentRect)) {
-            mPopup.updateCoordinates(mContentRect);
-        }
-        mWidthChanged = false;
-        mPreviousContentRect.set(mContentRect);
+        mPopup.show(menuItems, mMenuItemClickListener, mContentRect);
     }
 
     /**
diff --git a/core/java/com/android/internal/widget/floatingtoolbar/FloatingToolbarPopup.java b/core/java/com/android/internal/widget/floatingtoolbar/FloatingToolbarPopup.java
new file mode 100644
index 0000000..f47700c
--- /dev/null
+++ b/core/java/com/android/internal/widget/floatingtoolbar/FloatingToolbarPopup.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.widget.floatingtoolbar;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.selectiontoolbar.SelectionToolbarManager;
+import android.widget.PopupWindow;
+
+import java.util.List;
+
+/**
+ * A popup window used by the {@link FloatingToolbar} to render menu items.
+ *
+ */
+public interface FloatingToolbarPopup {
+
+    /**
+     * Sets the suggested dp width of this floating toolbar.
+     * The actual width will be about this size but there are no guarantees that it will be exactly
+     * the suggested width.
+     */
+    void setSuggestedWidth(int suggestedWidth);
+
+    /**
+     * Sets if the floating toolbar width changed.
+     */
+    void setWidthChanged(boolean widthChanged);
+
+    /**
+     * Shows this popup at the specified coordinates.
+     * The specified coordinates may be adjusted to make sure the popup is entirely on-screen.
+     */
+    void show(List<MenuItem> menuItems, MenuItem.OnMenuItemClickListener menuItemClickListener,
+            Rect contentRect);
+
+    /**
+     * Gets rid of this popup. If the popup isn't currently showing, this will be a no-op.
+     */
+    void dismiss();
+
+    /**
+     * Hides this popup. This is a no-op if this popup is not showing.
+     * Use {@link #isHidden()} to distinguish between a hidden and a dismissed popup.
+     */
+    void hide();
+
+    /**
+     * Returns {@code true} if this popup is currently showing. {@code false} otherwise.
+     */
+    boolean isShowing();
+
+    /**
+     * Returns {@code true} if this popup is currently hidden. {@code false} otherwise.
+     */
+    boolean isHidden();
+
+    /**
+     * Makes this toolbar "outside touchable" and sets the onDismissListener.
+     *
+     * @param outsideTouchable if true, the popup will be made "outside touchable" and
+     *      "non focusable". The reverse will happen if false.
+     * @param onDismiss
+     *
+     * @return true if the "outsideTouchable" setting was modified. Otherwise returns false
+     *
+     * @see PopupWindow#setOutsideTouchable(boolean)
+     * @see PopupWindow#setFocusable(boolean)
+     * @see PopupWindow.OnDismissListener
+     */
+    boolean setOutsideTouchable(boolean outsideTouchable, PopupWindow.OnDismissListener onDismiss);
+
+    /**
+     * Returns {@link RemoteFloatingToolbarPopup} implementation if the system selection toolbar
+     * enabled, otherwise returns {@link LocalFloatingToolbarPopup} implementation.
+     */
+    static FloatingToolbarPopup createInstance(Context context, View parent) {
+        boolean enabled = SelectionToolbarManager.isRemoteSelectionToolbarEnabled(context);
+        return enabled
+                ? new RemoteFloatingToolbarPopup(context, parent)
+                : new LocalFloatingToolbarPopup(context, parent);
+    }
+
+}
diff --git a/core/java/com/android/internal/widget/FloatingToolbarPopup.java b/core/java/com/android/internal/widget/floatingtoolbar/LocalFloatingToolbarPopup.java
similarity index 96%
rename from core/java/com/android/internal/widget/FloatingToolbarPopup.java
rename to core/java/com/android/internal/widget/floatingtoolbar/LocalFloatingToolbarPopup.java
index e0388f6..80d8bd7 100644
--- a/core/java/com/android/internal/widget/FloatingToolbarPopup.java
+++ b/core/java/com/android/internal/widget/floatingtoolbar/LocalFloatingToolbarPopup.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.internal.widget;
+package com.android.internal.widget.floatingtoolbar;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -70,13 +70,13 @@
 import java.util.Objects;
 
 /**
- * A popup window used by the floating toolbar.
+ * A popup window used by the floating toolbar to render menu items in the local app process.
  *
  * This class is responsible for the rendering/animation of the floating toolbar.
  * It holds 2 panels (i.e. main panel and overflow panel) and an overflow button
  * to transition between panels.
  */
-public final class FloatingToolbarPopup {
+public final class LocalFloatingToolbarPopup implements FloatingToolbarPopup {
 
     /* Minimum and maximum number of items allowed in the overflow. */
     private static final int MIN_OVERFLOW_SIZE = 2;
@@ -94,7 +94,7 @@
     private final ViewGroup mContentContainer;  // holds all contents.
     private final ViewGroup mMainPanel;  // holds menu items that are initially displayed.
     // holds menu items hidden in the overflow.
-    private final FloatingToolbarPopup.OverflowPanel mOverflowPanel;
+    private final OverflowPanel mOverflowPanel;
     private final ImageButton mOverflowButton;  // opens/closes the overflow.
     /* overflow button drawables. */
     private final Drawable mArrow;
@@ -102,8 +102,7 @@
     private final AnimatedVectorDrawable mToArrow;
     private final AnimatedVectorDrawable mToOverflow;
 
-    private final FloatingToolbarPopup.OverflowPanelViewHelper
-            mOverflowPanelViewHelper;
+    private final OverflowPanelViewHelper mOverflowPanelViewHelper;
 
     /* Animation interpolators. */
     private final Interpolator mLogAccelerateInterpolator;
@@ -138,7 +137,7 @@
     private final int mIconTextSpacing;
 
     /**
-     * @see FloatingToolbarPopup.OverflowPanelViewHelper#preparePopupContent().
+     * @see OverflowPanelViewHelper#preparePopupContent().
      */
     private final Runnable mPreparePopupContentRTLHelper = new Runnable() {
         @Override
@@ -184,16 +183,20 @@
 
     private int mTransitionDurationScale;  // Used to scale the toolbar transition duration.
 
+    private final Rect mPreviousContentRect = new Rect();
+    private int mSuggestedWidth;
+    private boolean mWidthChanged = true;
+
     /**
      * Initializes a new floating toolbar popup.
      *
      * @param parent  A parent view to get the {@link android.view.View#getWindowToken()} token
      *      from.
      */
-    public FloatingToolbarPopup(Context context, View parent) {
+    public LocalFloatingToolbarPopup(Context context, View parent) {
         mParent = Objects.requireNonNull(parent);
         mContext = applyDefaultTheme(context);
-        mContentContainer = createContentContainer(context);
+        mContentContainer = createContentContainer(mContext);
         mPopupWindow = createPopupWindow(mContentContainer);
         mMarginHorizontal = parent.getResources()
                 .getDimensionPixelSize(R.dimen.floating_toolbar_horizontal_margin);
@@ -205,7 +208,7 @@
                 .getDimensionPixelSize(R.dimen.floating_toolbar_icon_text_spacing);
 
         // Interpolators
-        mLogAccelerateInterpolator = new FloatingToolbarPopup.LogAccelerateInterpolator();
+        mLogAccelerateInterpolator = new LogAccelerateInterpolator();
         mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(
                 mContext, android.R.interpolator.fast_out_slow_in);
         mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(
@@ -231,8 +234,7 @@
         mOverflowButton = createOverflowButton();
         mOverflowButtonSize = measure(mOverflowButton);
         mMainPanel = createMainPanel();
-        mOverflowPanelViewHelper =
-                new FloatingToolbarPopup.OverflowPanelViewHelper(mContext, mIconTextSpacing);
+        mOverflowPanelViewHelper = new OverflowPanelViewHelper(mContext, mIconTextSpacing);
         mOverflowPanel = createOverflowPanel();
 
         // Animation. Need views.
@@ -263,19 +265,7 @@
                 });
     }
 
-    /**
-     * Makes this toolbar "outside touchable" and sets the onDismissListener.
-     *
-     * @param outsideTouchable if true, the popup will be made "outside touchable" and
-     *      "non focusable". The reverse will happen if false.
-     * @param onDismiss
-     *
-     * @return true if the "outsideTouchable" setting was modified. Otherwise returns false
-     *
-     * @see PopupWindow#setOutsideTouchable(boolean)
-     * @see PopupWindow#setFocusable(boolean)
-     * @see PopupWindow.OnDismissListener
-     */
+    @Override
     public boolean setOutsideTouchable(
             boolean outsideTouchable, @Nullable PopupWindow.OnDismissListener onDismiss) {
         boolean ret = false;
@@ -293,7 +283,7 @@
      * Lays out buttons for the specified menu items.
      * Requires a subsequent call to {@link FloatingToolbar#show()} to show the items.
      */
-    public void layoutMenuItems(
+    private void layoutMenuItems(
             List<MenuItem> menuItems,
             MenuItem.OnMenuItemClickListener menuItemClickListener,
             int suggestedWidth) {
@@ -314,7 +304,7 @@
      *
      * @see #isLayoutRequired(List<MenuItem>)
      */
-    public void updateMenuItems(
+    private void updateMenuItems(
             List<MenuItem> menuItems, MenuItem.OnMenuItemClickListener menuItemClickListener) {
         mMenuItems.clear();
         for (MenuItem menuItem : menuItems) {
@@ -326,15 +316,42 @@
     /**
      * Returns true if this popup needs a relayout to properly render the specified menu items.
      */
-    public boolean isLayoutRequired(List<MenuItem> menuItems) {
+    private boolean isLayoutRequired(List<MenuItem> menuItems) {
         return !MenuItemRepr.reprEquals(menuItems, mMenuItems.values());
     }
 
-    /**
-     * Shows this popup at the specified coordinates.
-     * The specified coordinates may be adjusted to make sure the popup is entirely on-screen.
-     */
-    public void show(Rect contentRectOnScreen) {
+    @Override
+    public void setWidthChanged(boolean widthChanged) {
+        mWidthChanged = widthChanged;
+    }
+
+    @Override
+    public void setSuggestedWidth(int suggestedWidth) {
+        // Check if there's been a substantial width spec change.
+        int difference = Math.abs(suggestedWidth - mSuggestedWidth);
+        mWidthChanged = difference > (mSuggestedWidth * 0.2);
+        mSuggestedWidth = suggestedWidth;
+    }
+
+    @Override
+    public void show(List<MenuItem> menuItems,
+            MenuItem.OnMenuItemClickListener menuItemClickListener, Rect contentRect) {
+        if (isLayoutRequired(menuItems) || mWidthChanged) {
+            dismiss();
+            layoutMenuItems(menuItems, menuItemClickListener, mSuggestedWidth);
+        } else {
+            updateMenuItems(menuItems, menuItemClickListener);
+        }
+        if (!isShowing()) {
+            show(contentRect);
+        } else if (!mPreviousContentRect.equals(contentRect)) {
+            updateCoordinates(contentRect);
+        }
+        mWidthChanged = false;
+        mPreviousContentRect.set(contentRect);
+    }
+
+    private void show(Rect contentRectOnScreen) {
         Objects.requireNonNull(contentRectOnScreen);
 
         if (isShowing()) {
@@ -357,9 +374,7 @@
         runShowAnimation();
     }
 
-    /**
-     * Gets rid of this popup. If the popup isn't currently showing, this will be a no-op.
-     */
+    @Override
     public void dismiss() {
         if (mDismissed) {
             return;
@@ -373,10 +388,7 @@
         setZeroTouchableSurface();
     }
 
-    /**
-     * Hides this popup. This is a no-op if this popup is not showing.
-     * Use {@link #isHidden()} to distinguish between a hidden and a dismissed popup.
-     */
+    @Override
     public void hide() {
         if (!isShowing()) {
             return;
@@ -387,16 +399,12 @@
         setZeroTouchableSurface();
     }
 
-    /**
-     * Returns {@code true} if this popup is currently showing. {@code false} otherwise.
-     */
+    @Override
     public boolean isShowing() {
         return !mDismissed && !mHidden;
     }
 
-    /**
-     * Returns {@code true} if this popup is currently hidden. {@code false} otherwise.
-     */
+    @Override
     public boolean isHidden() {
         return mHidden;
     }
@@ -406,7 +414,7 @@
      * The specified coordinates may be adjusted to make sure the popup is entirely on-screen.
      * This is a no-op if this popup is not showing.
      */
-    public void updateCoordinates(Rect contentRectOnScreen) {
+    private void updateCoordinates(Rect contentRectOnScreen) {
         Objects.requireNonNull(contentRectOnScreen);
 
         if (!isShowing() || !mPopupWindow.isShowing()) {
@@ -1206,9 +1214,8 @@
         return overflowButton;
     }
 
-    private FloatingToolbarPopup.OverflowPanel createOverflowPanel() {
-        final FloatingToolbarPopup.OverflowPanel
-                overflowPanel = new FloatingToolbarPopup.OverflowPanel(this);
+    private OverflowPanel createOverflowPanel() {
+        final OverflowPanel overflowPanel = new OverflowPanel(this);
         overflowPanel.setLayoutParams(new ViewGroup.LayoutParams(
                 ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
         overflowPanel.setDivider(null);
@@ -1307,9 +1314,9 @@
      */
     private static final class OverflowPanel extends ListView {
 
-        private final FloatingToolbarPopup mPopup;
+        private final LocalFloatingToolbarPopup mPopup;
 
-        OverflowPanel(FloatingToolbarPopup popup) {
+        OverflowPanel(LocalFloatingToolbarPopup popup) {
             super(Objects.requireNonNull(popup).mContext);
             this.mPopup = popup;
             setScrollBarDefaultDelayBeforeFade(ViewConfiguration.getScrollDefaultDelay() * 3);
diff --git a/core/java/com/android/internal/widget/floatingtoolbar/OWNERS b/core/java/com/android/internal/widget/floatingtoolbar/OWNERS
new file mode 100644
index 0000000..ed9425c
--- /dev/null
+++ b/core/java/com/android/internal/widget/floatingtoolbar/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/view/selectiontoolbar/OWNERS
diff --git a/core/java/com/android/internal/widget/floatingtoolbar/RemoteFloatingToolbarPopup.java b/core/java/com/android/internal/widget/floatingtoolbar/RemoteFloatingToolbarPopup.java
new file mode 100644
index 0000000..b3a8128
--- /dev/null
+++ b/core/java/com/android/internal/widget/floatingtoolbar/RemoteFloatingToolbarPopup.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.widget.floatingtoolbar;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.selectiontoolbar.SelectionToolbarManager;
+import android.widget.PopupWindow;
+
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * A popup window used by the floating toolbar to render menu items in the remote system process.
+ *
+ * It holds 2 panels (i.e. main panel and overflow panel) and an overflow button
+ * to transition between panels.
+ */
+public final class RemoteFloatingToolbarPopup implements FloatingToolbarPopup {
+
+    private final SelectionToolbarManager mSelectionToolbarManager;
+    // Parent for the popup window.
+    private final View mParent;
+
+    public RemoteFloatingToolbarPopup(Context context, View parent) {
+        // TODO: implement it
+        mParent = Objects.requireNonNull(parent);
+        mSelectionToolbarManager = context.getSystemService(SelectionToolbarManager.class);
+    }
+
+    @Override
+    public void show(List<MenuItem> menuItems,
+            MenuItem.OnMenuItemClickListener menuItemClickListener, Rect contentRect) {
+        // TODO: implement it
+    }
+
+    @Override
+    public void hide() {
+        // TODO: implement it
+    }
+
+    @Override
+    public void setSuggestedWidth(int suggestedWidth) {
+        // TODO: implement it
+    }
+
+    @Override
+    public void setWidthChanged(boolean widthChanged) {
+        // no-op
+    }
+
+    @Override
+    public void dismiss() {
+        // TODO: implement it
+    }
+
+    @Override
+    public boolean isHidden() {
+        return false;
+    }
+
+    @Override
+    public boolean isShowing() {
+        return false;
+    }
+
+    @Override
+    public boolean setOutsideTouchable(boolean outsideTouchable,
+            PopupWindow.OnDismissListener onDismiss) {
+        return false;
+    }
+}
diff --git a/core/java/com/android/server/NetworkManagementSocketTagger.java b/core/java/com/android/server/NetworkManagementSocketTagger.java
index 26ff192..d89566c9 100644
--- a/core/java/com/android/server/NetworkManagementSocketTagger.java
+++ b/core/java/com/android/server/NetworkManagementSocketTagger.java
@@ -70,8 +70,8 @@
             Log.d(TAG, "tagSocket(" + fd.getInt$() + ") with statsTag=0x"
                     + Integer.toHexString(options.statsTag) + ", statsUid=" + options.statsUid);
         }
-        if (options.statsTag == -1 && StrictMode.vmUntaggedSocketEnabled()) {
-            StrictMode.onUntaggedSocket();
+        if (options.statsTag == -1) {
+            StrictMode.noteUntaggedSocket();
         }
         // TODO: skip tagging when options would be no-op
         tagSocketFd(fd, options.statsTag, options.statsUid);
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index d66f461..39f17e5 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -849,8 +849,8 @@
                             XmlUtils.skipCurrentTag(parser);
                         }
                     } break;
-                    case "updatable-library":
-                        // "updatable-library" is meant to behave exactly like "library"
+                    case "apex-library":
+                        // "apex-library" is meant to behave exactly like "library"
                     case "library": {
                         if (allowLibs) {
                             String lname = parser.getAttributeValue(null, "name");
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 04fafb4..21ec64b 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -232,8 +232,7 @@
 // TODO: Rename the server-level flag or remove.
 static const char* ENABLE_JITZYGOTE_IMAGE = "enable_apex_image";
 // Flag to pass to the runtime when using the JIT Zygote image.
-static const char* kJitZygoteImageOption =
-        "-Ximage:boot.art:/nonx/boot-framework.art!/system/etc/boot-image.prof";
+static const char* kJitZygoteImageOption = "-Xforcejitzygote";
 
 // Feature flag name for disabling lock profiling.
 static const char* DISABLE_LOCK_PROFILING = "disable_lock_profiling";
@@ -987,9 +986,9 @@
                         "--instruction-set-features=", "-Xcompiler-option");
 
     /*
-     * When running with debug.generate-debug-info, add --generate-debug-info to
-     * the compiler options so that both JITted code and the boot image extension,
-     * if it is compiled on device, will include native debugging information.
+     * When running with debug.generate-debug-info, add --generate-debug-info to the compiler
+     * options so that both JITted code and the boot image, if it is compiled on device, will
+     * include native debugging information.
      */
     property_get("debug.generate-debug-info", propBuf, "");
     bool generate_debug_info = (strcmp(propBuf, "true") == 0);
@@ -1012,7 +1011,7 @@
     property_get("dalvik.vm.extra-opts", extraOptsBuf, "");
     parseExtraOpts(extraOptsBuf, NULL);
 
-    // Extra options for boot image extension generation.
+    // Extra options for boot image generation.
     if (skip_compilation) {
         addOption("-Xnoimage-dex2oat");
     } else {
@@ -1035,8 +1034,8 @@
         parseCompilerOption("dalvik.vm.image-dex2oat-cpu-set", dex2oatCpuSetImageBuf, "--cpu-set=",
                             "-Ximage-compiler-option");
 
-        // The runtime may compile a boot image extension, when necessary, not using installd.
-        // Thus, we need to pass the instruction-set-features/variant as an image-compiler-option.
+        // The runtime may compile a boot image, when necessary, not using installd. Thus, we need
+        // to pass the instruction-set-features/variant as an image-compiler-option.
         // Note: it is OK to reuse the buffer, as the values are exactly the same between
         //       * compiler-option, used for runtime compilation (DexClassLoader)
         //       * image-compiler-option, used for boot-image compilation on device
diff --git a/core/jni/OWNERS b/core/jni/OWNERS
index f2bcb02..4357729 100644
--- a/core/jni/OWNERS
+++ b/core/jni/OWNERS
@@ -59,13 +59,17 @@
 per-file android_media_midi_* = file:/media/java/android/media/midi/OWNERS
 per-file android_opengl_* = file:/opengl/java/android/opengl/OWNERS
 per-file android_os_storage_* = file:/core/java/android/os/storage/OWNERS
-per-file android_se_* = file:/core/java/android/se/OWNERS
+per-file android_se_* = file:/omapi/java/android/se/OWNERS
 per-file android_security_* = file:/core/java/android/security/OWNERS
 per-file android_view_* = file:/core/java/android/view/OWNERS
 per-file com_android_internal_net_* = file:/services/core/java/com/android/server/net/OWNERS
 
 ### Graphics ###
 per-file android_graphics_* = file:/graphics/java/android/graphics/OWNERS
+
+### Text ###
+per-file android_text_* = file:/core/java/android/text/OWNERS
+
 # These are highly common-use files
 per-file Android.bp = file:/graphics/java/android/graphics/OWNERS
 per-file AndroidRuntime.cpp = file:/graphics/java/android/graphics/OWNERS
diff --git a/core/jni/android_graphics_BLASTBufferQueue.cpp b/core/jni/android_graphics_BLASTBufferQueue.cpp
index 78e5adc..55f1369 100644
--- a/core/jni/android_graphics_BLASTBufferQueue.cpp
+++ b/core/jni/android_graphics_BLASTBufferQueue.cpp
@@ -37,16 +37,6 @@
     return reinterpret_cast<jlong>(queue.get());
 }
 
-static jlong nativeCreateAndUpdate(JNIEnv* env, jclass clazz, jstring jName, jlong surfaceControl,
-                                   jlong width, jlong height, jint format) {
-    ScopedUtfChars name(env, jName);
-    sp<BLASTBufferQueue> queue =
-            new BLASTBufferQueue(name.c_str(), reinterpret_cast<SurfaceControl*>(surfaceControl),
-                                 width, height, format);
-    queue->incStrong((void*)nativeCreate);
-    return reinterpret_cast<jlong>(queue.get());
-}
-
 static void nativeDestroy(JNIEnv* env, jclass clazz, jlong ptr) {
     sp<BLASTBufferQueue> queue = reinterpret_cast<BLASTBufferQueue*>(ptr);
     queue->decStrong((void*)nativeCreate);
@@ -91,11 +81,15 @@
     queue->applyPendingTransactions(frameNum);
 }
 
+static bool nativeIsSameSurfaceControl(JNIEnv* env, jclass clazz, jlong ptr, jlong surfaceControl) {
+    sp<BLASTBufferQueue> queue = reinterpret_cast<BLASTBufferQueue*>(ptr);
+    return queue->isSameSurfaceControl(reinterpret_cast<SurfaceControl*>(surfaceControl));
+}
+
 static const JNINativeMethod gMethods[] = {
         /* name, signature, funcPtr */
         // clang-format off
         {"nativeCreate", "(Ljava/lang/String;)J", (void*)nativeCreate},
-        {"nativeCreateAndUpdate", "(Ljava/lang/String;JJJI)J", (void*)nativeCreateAndUpdate},
         {"nativeGetSurface", "(JZ)Landroid/view/Surface;", (void*)nativeGetSurface},
         {"nativeDestroy", "(J)V", (void*)nativeDestroy},
         {"nativeSetSyncTransaction", "(JJZ)V", (void*)nativeSetSyncTransaction},
@@ -103,6 +97,7 @@
         {"nativeMergeWithNextTransaction", "(JJJ)V", (void*)nativeMergeWithNextTransaction},
         {"nativeGetLastAcquiredFrameNum", "(J)J", (void*)nativeGetLastAcquiredFrameNum},
         {"nativeApplyPendingTransactions", "(JJ)V", (void*)nativeApplyPendingTransactions},
+        {"nativeIsSameSurfaceControl", "(JJ)Z", (void*)nativeIsSameSurfaceControl},
         // clang-format on
 };
 
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 8b45907..3e2b258 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -2774,6 +2774,46 @@
     return canBeSpatialized;
 }
 
+// keep these values in sync with AudioSystem.java
+#define DIRECT_NOT_SUPPORTED 0
+#define DIRECT_OFFLOAD_SUPPORTED 1
+#define DIRECT_OFFLOAD_GAPLESS_SUPPORTED 3
+#define DIRECT_BITSTREAM_SUPPORTED 4
+
+static jint convertAudioDirectModeFromNative(audio_direct_mode_t directMode) {
+    jint result = DIRECT_NOT_SUPPORTED;
+    if ((directMode & AUDIO_DIRECT_OFFLOAD_SUPPORTED) != AUDIO_DIRECT_NOT_SUPPORTED) {
+        result |= DIRECT_OFFLOAD_SUPPORTED;
+    }
+    if ((directMode & AUDIO_DIRECT_OFFLOAD_GAPLESS_SUPPORTED) != AUDIO_DIRECT_NOT_SUPPORTED) {
+        result |= DIRECT_OFFLOAD_GAPLESS_SUPPORTED;
+    }
+    if ((directMode & AUDIO_DIRECT_BITSTREAM_SUPPORTED) != AUDIO_DIRECT_NOT_SUPPORTED) {
+        result |= DIRECT_BITSTREAM_SUPPORTED;
+    }
+    return result;
+}
+
+static jint android_media_AudioSystem_getDirectPlaybackSupport(JNIEnv *env, jobject thiz,
+                                                               jobject jFormat, jobject jaa) {
+    JNIAudioAttributeHelper::UniqueAaPtr paa = JNIAudioAttributeHelper::makeUnique();
+    jint jStatus = JNIAudioAttributeHelper::nativeFromJava(env, jaa, paa.get());
+    if (jStatus != (jint)AUDIO_JAVA_SUCCESS) {
+        return DIRECT_NOT_SUPPORTED;
+    }
+
+    audio_config_t nConfig;
+    javaAudioFormatToNativeAudioConfig(env, &nConfig, jFormat, false /*isInput*/);
+
+    audio_direct_mode_t directMode;
+    status_t status = AudioSystem::getDirectPlaybackSupport(paa.get(), &nConfig, &directMode);
+    if (status != NO_ERROR) {
+        ALOGW("%s native returned error %d", __func__, status);
+        return DIRECT_NOT_SUPPORTED;
+    }
+    return convertAudioDirectModeFromNative(directMode);
+}
+
 // ----------------------------------------------------------------------------
 
 static const JNINativeMethod gMethods[] =
@@ -2917,7 +2957,10 @@
          {"canBeSpatialized",
           "(Landroid/media/AudioAttributes;Landroid/media/AudioFormat;"
           "[Landroid/media/AudioDeviceAttributes;)Z",
-          (void *)android_media_AudioSystem_canBeSpatialized}};
+          (void *)android_media_AudioSystem_canBeSpatialized},
+         {"getDirectPlaybackSupport",
+          "(Landroid/media/AudioFormat;Landroid/media/AudioAttributes;)I",
+          (void *)android_media_AudioSystem_getDirectPlaybackSupport}};
 
 static const JNINativeMethod gEventHandlerMethods[] = {
     {"native_setup",
diff --git a/core/jni/android_text_Hyphenator.cpp b/core/jni/android_text_Hyphenator.cpp
index 21402b6..011e051 100644
--- a/core/jni/android_text_Hyphenator.cpp
+++ b/core/jni/android_text_Hyphenator.cpp
@@ -83,16 +83,20 @@
     constexpr int INDIC_MIN_PREFIX = 2;
     constexpr int INDIC_MIN_SUFFIX = 2;
 
+    addHyphenator("af", 1, 1);  // Afrikaans
+    addHyphenator("am", 1, 1);  // Amharic
     addHyphenator("as", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX);  // Assamese
     addHyphenator("be", 2, 2);  // Belarusian
     addHyphenator("bg", 2, 2);  // Bulgarian
     addHyphenator("bn", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX);  // Bengali
+    addHyphenator("cs", 2, 2);  // Czech
     addHyphenator("cu", 1, 2);  // Church Slavonic
     addHyphenator("cy", 2, 3);  // Welsh
     addHyphenator("da", 2, 2);  // Danish
     addHyphenator("de-1901", 2, 2);  // German 1901 orthography
     addHyphenator("de-1996", 2, 2);  // German 1996 orthography
     addHyphenator("de-CH-1901", 2, 2);  // Swiss High German 1901 orthography
+    addHyphenator("el", 1, 1);  // Greek
     addHyphenator("en-GB", 2, 3);  // British English
     addHyphenator("en-US", 2, 3);  // American English
     addHyphenator("es", 2, 2);  // Spanish
@@ -100,6 +104,7 @@
     addHyphenator("eu", 2, 2);  // Basque
     addHyphenator("fr", 2, 3);  // French
     addHyphenator("ga", 2, 3);  // Irish
+    addHyphenator("gl", 2, 2);  // Galician
     addHyphenator("gu", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX);  // Gujarati
     addHyphenator("hi", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX);  // Hindi
     addHyphenator("hr", 2, 2);  // Croatian
@@ -107,20 +112,28 @@
     // texhyphen sources say Armenian may be (1, 2); but that it needs confirmation.
     // Going with a more conservative value of (2, 2) for now.
     addHyphenator("hy", 2, 2);  // Armenian
+    addHyphenator("it", 2, 2);  // Italian
+    addHyphenator("ka", 1, 2);  // Georgian
     addHyphenator("kn", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX);  // Kannada
     addHyphenator("la", 2, 2);  // Latin
+    addHyphenator("lt", 2, 2);  // Lithuanian
+    addHyphenator("lv", 2, 2);  // Latvian
     addHyphenator("ml", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX);  // Malayalam
     addHyphenator("mn-Cyrl", 2, 2);  // Mongolian in Cyrillic script
     addHyphenator("mr", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX);  // Marathi
     addHyphenator("nb", 2, 2);  // Norwegian Bokmål
+    addHyphenator("nl", 2, 2);  // Dutch
     addHyphenator("nn", 2, 2);  // Norwegian Nynorsk
     addHyphenator("or", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX);  // Oriya
     addHyphenator("pa", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX);  // Punjabi
     addHyphenator("pt", 2, 3);  // Portuguese
+    addHyphenator("sk", 2, 2);  // Slovak
     addHyphenator("sl", 2, 2);  // Slovenian
+    addHyphenator("sq", 2, 2);  // Albanian
     addHyphenator("ta", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX);  // Tamil
     addHyphenator("te", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX);  // Telugu
     addHyphenator("tk", 2, 2);  // Turkmen
+    addHyphenator("uk", 2, 2);  // Ukrainian
     addHyphenator("und-Ethi", 1, 1);  // Any language in Ethiopic script
 
     // Following two hyphenators do not have pattern files but there is some special logic based on
diff --git a/core/proto/android/inputmethodservice/softinputwindow.proto b/core/proto/android/inputmethodservice/softinputwindow.proto
index 85b7d73..e0ba6bf 100644
--- a/core/proto/android/inputmethodservice/softinputwindow.proto
+++ b/core/proto/android/inputmethodservice/softinputwindow.proto
@@ -23,10 +23,10 @@
 option java_multiple_files = true;
 
 message SoftInputWindowProto {
-    optional string name = 1;
-    optional int32 window_type = 2;
-    optional int32 gravity = 3;
-    optional bool takes_focus = 4;
+    reserved 1;  // name
+    reserved 2;  // window_type
+    reserved 3;  // gravity
+    reserved 4;  // takes_focus
     optional .android.graphics.RectProto bounds = 5;
     optional int32 window_state = 6;
 }
\ No newline at end of file
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index b406578..f76b211 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -716,8 +716,6 @@
 
     optional SettingProto nr_nsa_tracking_screen_off_mode = 153 [ (android.privacy).dest = DEST_AUTOMATIC ];
 
-    optional SettingProto nsd_on = 83 [ (android.privacy).dest = DEST_AUTOMATIC ];
-
     message Ntp {
         option (android.msg_privacy).dest = DEST_EXPLICIT;
 
diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto
index ba4a5b0..00b7fd7 100644
--- a/core/proto/android/providers/settings/secure.proto
+++ b/core/proto/android/providers/settings/secure.proto
@@ -85,6 +85,7 @@
         optional SettingProto accessibility_floating_menu_icon_type = 39 [ (android.privacy).dest = DEST_AUTOMATIC ];
         optional SettingProto accessibility_floating_menu_opacity = 40 [ (android.privacy).dest = DEST_AUTOMATIC ];
         optional SettingProto accessibility_floating_menu_fade_enabled = 41 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto odi_captions_volume_ui_enabled = 42 [ (android.privacy).dest = DEST_AUTOMATIC ];
     }
     optional Accessibility accessibility = 2;
 
@@ -382,6 +383,7 @@
 
     optional SettingProto multi_press_timeout = 38 [ (android.privacy).dest = DEST_AUTOMATIC ];
 
+    optional SettingProto nav_bar_kids_mode = 91 [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingProto navigation_mode = 76 [ (android.privacy).dest = DEST_AUTOMATIC ];
 
     message NfcPayment {
@@ -664,5 +666,5 @@
 
     // Please insert fields in alphabetical order and group them into messages
     // if possible (to avoid reaching the method limit).
-    // Next tag = 91;
+    // Next tag = 92;
 }
diff --git a/core/proto/android/service/package.proto b/core/proto/android/service/package.proto
index 48feb4d..1dedbb9 100644
--- a/core/proto/android/service/package.proto
+++ b/core/proto/android/service/package.proto
@@ -112,6 +112,8 @@
         optional string last_disabled_app_caller = 8;
         repeated string suspending_package = 9;
         optional int32 distraction_flags = 10;
+        // UTC timestamp of first install for the user
+        optional int32 first_install_time_ms = 11;
     }
 
     message InstallSourceProto {
@@ -147,8 +149,7 @@
     optional int32 version_code = 3;
     // Package's reported version string (what's displayed to the user).
     optional string version_string = 4;
-    // UTC timestamp of install
-    optional int64 install_time_ms = 5;
+    reserved 5;
     // Millisecond UTC timestamp of latest update adjusted to Google's server clock.
     optional int64 update_time_ms = 6;
     // From "dumpsys package" - name of package which installed this one.
diff --git a/core/proto/android/view/imeinsetssourceconsumer.proto b/core/proto/android/view/imeinsetssourceconsumer.proto
index 1b9aff9..b1ed365 100644
--- a/core/proto/android/view/imeinsetssourceconsumer.proto
+++ b/core/proto/android/view/imeinsetssourceconsumer.proto
@@ -16,7 +16,6 @@
 
 syntax = "proto2";
 
-import "frameworks/base/core/proto/android/view/inputmethod/editorinfo.proto";
 import "frameworks/base/core/proto/android/view/insetssourceconsumer.proto";
 
 package android.view;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index e2a2ac6..a005eb0 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -714,6 +714,9 @@
     <protected-broadcast android:name="android.app.action.SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED" />
     <protected-broadcast android:name="android.app.action.SHOW_NEW_USER_DISCLAIMER" />
 
+    <!-- Added in T -->
+    <protected-broadcast android:name="android.intent.action.REFRESH_SAFETY_SOURCES" />
+
     <!-- ====================================================================== -->
     <!--                          RUNTIME PERMISSIONS                           -->
     <!-- ====================================================================== -->
@@ -1489,8 +1492,26 @@
         android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_bodySensors"
         android:description="@string/permdesc_bodySensors"
+        android:backgroundPermission="android.permission.BODY_SENSORS_BACKGROUND"
         android:protectionLevel="dangerous" />
 
+    <!-- Allows an application to access data from sensors that the user uses to measure what is
+         happening inside their body, such as heart rate. If you're requesting this permission, you
+         must also request {@link #BODY_SENSORS}. Requesting this permission by itself doesn't give
+         you Body sensors access.
+         <p>Protection level: dangerous
+
+         <p> This is a hard restricted permission which cannot be held by an app until
+         the installer on record allowlists the permission. For more details see
+         {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
+    -->
+    <permission android:name="android.permission.BODY_SENSORS_BACKGROUND"
+        android:permissionGroup="android.permission-group.UNDEFINED"
+        android:label="@string/permlab_bodySensors_background"
+        android:description="@string/permdesc_bodySensors_background"
+        android:protectionLevel="dangerous"
+        android:permissionFlags="hardRestricted" />
+
     <!-- Allows an app to use fingerprint hardware.
          <p>Protection level: normal
          @deprecated Applications should request {@link
@@ -5461,6 +5482,16 @@
         android:protectionLevel="signature|installer" />
 
     <!--
+        @SystemApi
+        Allows the holder to start the screen to review permission decisions.
+        <p>Protection level: signature|installer
+        @hide -->
+    <permission android:name="android.permission.START_REVIEW_PERMISSION_DECISIONS"
+        android:label="@string/permlab_startReviewPermissionDecisions"
+        android:description="@string/permdesc_startReviewPermissionDecisions"
+        android:protectionLevel="signature|installer" />
+
+    <!--
         Allows the holder to start the screen with a list of app features.
         <p>Protection level: signature|installer
     -->
@@ -6071,6 +6102,13 @@
     <permission android:name="android.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES"
                 android:protectionLevel="signature|role" />
     
+    <!-- @SystemApi Allows an app to read whether SafetyCenter is enabled/disabled.
+             <p>Protection level: signature|privileged
+             @hide
+        -->
+    <permission android:name="android.permission.READ_SAFETY_CENTER_STATUS"
+        android:protectionLevel="signature|privileged" />
+
     <!-- Attribution for Geofencing service. -->
     <attribution android:tag="GeofencingService" android:label="@string/geofencing_service"/>
     <!-- Attribution for Country Detector. -->
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 585c372..ddaff68 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -1989,6 +1989,7 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Gepasmaakte programkennisgewing"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"Laat <xliff:g id="APP">%1$s</xliff:g> toe om \'n nuwe gebruiker met <xliff:g id="ACCOUNT">%2$s</xliff:g> te skep (\'n gebruiker met hierdie rekening bestaan reeds)?"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"Laat <xliff:g id="APP">%1$s</xliff:g> toe om \'n nuwe gebruiker met <xliff:g id="ACCOUNT">%2$s</xliff:g> te skep?"</string>
+    <string name="supervised_user_creation_label" msgid="6884904353827427515">"Voeg gebruiker onder toesig by"</string>
     <string name="language_selection_title" msgid="52674936078683285">"Voeg \'n taal by"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"Streekvoorkeur"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Voer taalnaam in"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index f338166..cee4da6 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -1989,6 +1989,8 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"ብጁ የመተግበሪያ ማሳወቂያ"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="APP">%1$s</xliff:g> በ<xliff:g id="ACCOUNT">%2$s</xliff:g> አዲስ ተጠቃሚ እንዲፈጥር ይፈቀድለት (ይህ መለያ ያለው ተጠቃሚ አስቀድሞ አለ)?"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="APP">%1$s</xliff:g> አዲስ ተጠቃሚ ከ <xliff:g id="ACCOUNT">%2$s</xliff:g> ጋር መፍጠር እንዲችል ይፍቀዱ?"</string>
+    <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+    <skip />
     <string name="language_selection_title" msgid="52674936078683285">"ቋንቋ ያክሉ"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"የክልል ምርጫ"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"የቋንቋ ስም ይተይቡ"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index c15f298..4927fa9 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -287,7 +287,7 @@
     <string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
     <string name="notification_hidden_text" msgid="2835519769868187223">"إشعار جديد"</string>
     <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"لوحة المفاتيح الافتراضية"</string>
-    <string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"لوحة المفاتيح الفعلية"</string>
+    <string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"لوحة المفاتيح الخارجية"</string>
     <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>
@@ -2117,6 +2117,8 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"إشعار تطبيق مخصّص"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"هل تسمح لتطبيق <xliff:g id="APP">%1$s</xliff:g> بإنشاء مستخدم جديد باستخدام <xliff:g id="ACCOUNT">%2$s</xliff:g> (يوجد مستخدم بهذا الحساب مسبقًا)؟"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"هل تسمح لتطبيق <xliff:g id="APP">%1$s</xliff:g> بإنشاء مستخدم جديد باستخدام <xliff:g id="ACCOUNT">%2$s</xliff:g> ؟"</string>
+    <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+    <skip />
     <string name="language_selection_title" msgid="52674936078683285">"إضافة لغة"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"تفضيل المنطقة"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"اكتب اسم اللغة"</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index 9dbfb2e..0c09239 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -1989,6 +1989,7 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"কাষ্টম এপৰ জাননী"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="APP">%1$s</xliff:g>ক <xliff:g id="ACCOUNT">%2$s</xliff:g>ৰ (এই একাউণ্টটোৰ এজন ব্যৱহাৰকাৰী ইতিমধ্যে আছে) জৰিয়তে এজন নতুন ব্যৱহাৰকাৰী সৃষ্টি কৰিবলৈ অনুমতি দিবনে ?"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="APP">%1$s</xliff:g>ক <xliff:g id="ACCOUNT">%2$s</xliff:g>ৰ জৰিয়তে এজন নতুন ব্যৱহাৰকাৰী সৃষ্টি কৰিবলৈ অনুমতি দিবনে?"</string>
+    <string name="supervised_user_creation_label" msgid="6884904353827427515">"নিৰীক্ষণত থকা ব্যৱহাৰকাৰী যোগ দিয়ক"</string>
     <string name="language_selection_title" msgid="52674936078683285">"ভাষা যোগ কৰক"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"অঞ্চলৰ অগ্ৰাধিকাৰ"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"ভাষাৰ নাম লিখক"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 1c93552..a11b68d 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -1989,6 +1989,7 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Fərdi tətbiq bildirişi"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="APP">%1$s</xliff:g> tətbiqinə <xliff:g id="ACCOUNT">%2$s</xliff:g> (artıq bu hesabı olan İstifadəçi mövcuddur) ilə yeni İstifadəçi yaratmağa icazə verilsin?"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="APP">%1$s</xliff:g> tətbiqinə <xliff:g id="ACCOUNT">%2$s</xliff:g> ilə yeni İstifadəçi yartmağa icazə verilsin?"</string>
+    <string name="supervised_user_creation_label" msgid="6884904353827427515">"Nəzarət edilən istifadəçi əlavə edin"</string>
     <string name="language_selection_title" msgid="52674936078683285">"Dil əlavə edin"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"Region seçimi"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Dil adını daxil 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 9241631..b8e0d9a 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -2021,6 +2021,7 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Prilagođeno obaveštenje o aplikaciji"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"Želite li da dozvolite da <xliff:g id="APP">%1$s</xliff:g> napravi novog korisnika sa nalogom <xliff:g id="ACCOUNT">%2$s</xliff:g> (korisnik sa tim nalogom već postoji)?"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"Želite li da dozvolite da <xliff:g id="APP">%1$s</xliff:g> napravi novog korisnika sa nalogom <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+    <string name="supervised_user_creation_label" msgid="6884904353827427515">"Dodajte korisnika pod nadzorom"</string>
     <string name="language_selection_title" msgid="52674936078683285">"Dodajte jezik"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"Podešavanje regiona"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Unesite naziv jezika"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 849d53b..26d2e73 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -2053,6 +2053,8 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Апавяшчэнне пра карыстальніцкую праграму"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"Дазволіць праграме \"<xliff:g id="APP">%1$s</xliff:g>\" стварыць новага Карыстальніка з уліковым запісам <xliff:g id="ACCOUNT">%2$s</xliff:g> (Карыстальнік з гэтым уліковым запісам ужо існуе)?"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"Дазволіць праграме \"<xliff:g id="APP">%1$s</xliff:g>\" стварыць новага Карыстальніка з уліковым запісам <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+    <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+    <skip />
     <string name="language_selection_title" msgid="52674936078683285">"Дадаць мову"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"Параметры рэгіёна"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Увядзіце назву мовы"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index dad2f03..5250956 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -1989,6 +1989,7 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Персонализирано известие за приложение"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"Да се разреши ли на <xliff:g id="APP">%1$s</xliff:g> да създаде нов потребител с профила <xliff:g id="ACCOUNT">%2$s</xliff:g> (вече съществува потребител с този профил)?"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"Да се разреши ли на <xliff:g id="APP">%1$s</xliff:g> да създаде нов потребител с профила <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+    <string name="supervised_user_creation_label" msgid="6884904353827427515">"Добавяне на контролиран потребител"</string>
     <string name="language_selection_title" msgid="52674936078683285">"Добавяне на език"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"Предпочитание за региона"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Въведете име на език"</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index d560d5c..657596f 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -1989,6 +1989,8 @@
     <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>
     <string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="ACCOUNT">%2$s</xliff:g>-এ একজন নতুন ব্যবহারকারী তৈরি করার অনুমতি <xliff:g id="APP">%1$s</xliff:g>-কে দেবেন?"</string>
+    <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+    <skip />
     <string name="language_selection_title" msgid="52674936078683285">"একটি ভাষা যোগ করুন"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"পছন্দের অঞ্চল"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"ভাষার নাম লিখুন"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 68ccf15..6e8cd97 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -331,19 +331,19 @@
     <string name="permgroupdesc_sensors" msgid="2610631290633747752">"pristupa podacima senzora o vašim vitalnim funkcijama"</string>
     <string name="permgrouplab_notifications" msgid="5472972361980668884">"Obavještenja"</string>
     <string name="permgroupdesc_notifications" msgid="4608679556801506580">"prikaz obavještenja"</string>
-    <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Preuzima sadržaj prozora"</string>
+    <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"preuzima sadržaj prozora"</string>
     <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Pregleda sadržaj prozora koji trenutno koristite."</string>
-    <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Uključi opciju Istraživanje dodirom"</string>
+    <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"uključi opciju Istraživanje dodirom"</string>
     <string name="capability_desc_canRequestTouchExploration" msgid="4394677060796752976">"Stavke koje dodirnete bit će izgovorene naglas, a ekran možete istraživati koristeći pokrete."</string>
-    <string name="capability_title_canRequestFilterKeyEvents" msgid="2772371671541753254">"Prati tekst koji unosite"</string>
+    <string name="capability_title_canRequestFilterKeyEvents" msgid="2772371671541753254">"prati tekst koji unosite"</string>
     <string name="capability_desc_canRequestFilterKeyEvents" msgid="2381315802405773092">"Obuhvata lične podatke kao što su brojevi kreditnih kartica i lozinke."</string>
-    <string name="capability_title_canControlMagnification" msgid="7701572187333415795">"Kontrolira uvećavanje prikaza na ekranu"</string>
+    <string name="capability_title_canControlMagnification" msgid="7701572187333415795">"kontrolira uvećavanje prikaza na ekranu"</string>
     <string name="capability_desc_canControlMagnification" msgid="2206586716709254805">"Kontrolira stepen uvećanja prikaza na ekranu i podešavanje položaja."</string>
-    <string name="capability_title_canPerformGestures" msgid="9106545062106728987">"Praviti pokrete"</string>
+    <string name="capability_title_canPerformGestures" msgid="9106545062106728987">"izvodi pokrete"</string>
     <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"Može dodirivati, prevlačiti, hvatati prstima i praviti druge pokrete."</string>
-    <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"Pokreti otiska prsta"</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"prepoznaje pokrete za otisak prsta"</string>
     <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"Moguće je zabilježiti pokrete na senzoru za otisak prsta uređaja."</string>
-    <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"Snimanje ekrana"</string>
+    <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"pravi snimke ekrana"</string>
     <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"Moguće je snimiti ekran."</string>
     <string name="permlab_statusBar" msgid="8798267849526214017">"onemogućavanje ili mijenjanje statusne trake"</string>
     <string name="permdesc_statusBar" msgid="5809162768651019642">"Dozvoljava aplikaciji onemogućavanje statusne trake ili dodavanje i uklanjanje sistemskih ikona."</string>
@@ -1920,7 +1920,7 @@
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Izbrisao je vaš administrator"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"Uredu"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Ušteda baterije uključuje tamnu temu i ograničava ili isključuje aktivnost u pozadini, određene vizuelne efekte i funkcije te neke mrežne veze."</string>
-    <string name="battery_saver_description" msgid="8518809702138617167">"Ušteda baterije uključuje Tamnu temu i ograničava ili isključuje aktivnost u pozadini, određene vizuelne efekte i funkcije te neke mrežne veze."</string>
+    <string name="battery_saver_description" msgid="8518809702138617167">"Ušteda baterije uključuje tamnu temu i ograničava ili isključuje aktivnost u pozadini, određene vizuelne efekte i funkcije te neke mrežne veze."</string>
     <string name="data_saver_description" msgid="4995164271550590517">"Radi smanjenja prijenosa podataka, Ušteda podataka sprečava da neke aplikacije šalju ili primaju podatke u pozadini. Aplikacija koju trenutno koristite može pristupiti podacima, ali će to činiti rjeđe. Naprimjer, to može značiti da se slike ne prikazuju dok ih ne dodirnete."</string>
     <string name="data_saver_enable_title" msgid="7080620065745260137">"Uključiti Uštedu podataka?"</string>
     <string name="data_saver_enable_button" msgid="4399405762586419726">"Uključi"</string>
@@ -2021,6 +2021,7 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Prilagođeno obavještenje aplikacije"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"Dozvoliti aplikaciji <xliff:g id="APP">%1$s</xliff:g> da kreira novog korisnika s računom <xliff:g id="ACCOUNT">%2$s</xliff:g> (korisnik s ovim računom već postoji)?"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"Dozvoliti aplikaciji <xliff:g id="APP">%1$s</xliff:g> da kreira novog korisnika s računom <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+    <string name="supervised_user_creation_label" msgid="6884904353827427515">"Dodaj korisnika pod nadzorom"</string>
     <string name="language_selection_title" msgid="52674936078683285">"Dodajte jezik"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"Izbor regije"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Upišite ime jezika"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 726bb3f..41af878 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -1989,6 +1989,8 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Notificació d\'aplicació personalitzada"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"Concedeixes permís a <xliff:g id="APP">%1$s</xliff:g> per crear un usuari amb el compte <xliff:g id="ACCOUNT">%2$s</xliff:g>? (Ja hi ha un usuari amb aquest compte.)"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"Concedeixes permís a <xliff:g id="APP">%1$s</xliff:g> per crear un usuari amb el compte <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+    <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+    <skip />
     <string name="language_selection_title" msgid="52674936078683285">"Afegeix un idioma"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"Preferència de regió"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Escriu el nom de l\'idioma"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index abbcc2c..72ad45b 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -2053,6 +2053,8 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Vlastní oznámení aplikace"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"Povolit aplikaci <xliff:g id="APP">%1$s</xliff:g> vytvořit nového uživatele s účtem <xliff:g id="ACCOUNT">%2$s</xliff:g>? (Uživatel s tímto účtem již existuje.)"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"Povolit aplikaci <xliff:g id="APP">%1$s</xliff:g> vytvořit nového uživatele s účtem <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+    <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+    <skip />
     <string name="language_selection_title" msgid="52674936078683285">"Přidat jazyk"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"Preferovaná oblast"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Zadejte název jazyka"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 57673f4..8f4039f 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -1989,6 +1989,8 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Tilpasset appnotifikation"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"Vil du give <xliff:g id="APP">%1$s</xliff:g> tilladelse til at oprette en ny bruger med <xliff:g id="ACCOUNT">%2$s</xliff:g> (der findes allerede en bruger med denne konto)?"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"Vil du give <xliff:g id="APP">%1$s</xliff:g> tilladelse til at oprette en nye bruger med <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+    <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+    <skip />
     <string name="language_selection_title" msgid="52674936078683285">"Tilføj et sprog"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"Områdeindstilling"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Angiv sprog"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index fde9b0c..5e5e578 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -1989,6 +1989,8 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Benutzerdefinierte App-Benachrichtigung"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"Es gibt bereits einen Nutzer mit <xliff:g id="ACCOUNT">%2$s</xliff:g>. Möchtest du zulassen, dass <xliff:g id="APP">%1$s</xliff:g> einen neuen Nutzer mit diesem Konto erstellt?"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"Möchtest du zulassen, dass <xliff:g id="APP">%1$s</xliff:g> einen neuen Nutzer mit <xliff:g id="ACCOUNT">%2$s</xliff:g> erstellt?"</string>
+    <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+    <skip />
     <string name="language_selection_title" msgid="52674936078683285">"Sprache hinzufügen"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"Region auswählen"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Sprache eingeben"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index b0ad4da..f184200 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -1989,6 +1989,8 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Προσαρμοσμένη ειδοποίηση εφαρμογής"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"Επιτρέπετε στην εφαρμογή <xliff:g id="APP">%1$s</xliff:g> να δημιουργήσει έναν νέο χρήστη με τον λογαριασμό <xliff:g id="ACCOUNT">%2$s</xliff:g> (υπάρχει ήδη χρήστης με αυτόν τον λογαριασμό);"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"Επιτρέπετε στην εφαρμογή <xliff:g id="APP">%1$s</xliff:g> να δημιουργήσει έναν νέο χρήστη με τον λογαριασμό <xliff:g id="ACCOUNT">%2$s</xliff:g>;"</string>
+    <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+    <skip />
     <string name="language_selection_title" msgid="52674936078683285">"Προσθήκη γλώσσας"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"Προτίμηση περιοχής"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Εισαγ. όνομα γλώσσας"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index fd68ddd..2bf964b 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -1989,6 +1989,7 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Custom app notification"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"Allow <xliff:g id="APP">%1$s</xliff:g> to create a new User with <xliff:g id="ACCOUNT">%2$s</xliff:g> (a User with this account already exists)?"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"Allow <xliff:g id="APP">%1$s</xliff:g> to create a new User with <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+    <string name="supervised_user_creation_label" msgid="6884904353827427515">"Add supervised user"</string>
     <string name="language_selection_title" msgid="52674936078683285">"Add a language"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"Region preference"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Type language name"</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 265d2e6..b4d1c82 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -1989,6 +1989,7 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Custom app notification"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"Allow <xliff:g id="APP">%1$s</xliff:g> to create a new User with <xliff:g id="ACCOUNT">%2$s</xliff:g> (a User with this account already exists)?"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"Allow <xliff:g id="APP">%1$s</xliff:g> to create a new User with <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+    <string name="supervised_user_creation_label" msgid="6884904353827427515">"Add supervised user"</string>
     <string name="language_selection_title" msgid="52674936078683285">"Add a language"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"Region preference"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Type language name"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 8ee21a3..e47a2c2 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -1989,6 +1989,7 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Custom app notification"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"Allow <xliff:g id="APP">%1$s</xliff:g> to create a new User with <xliff:g id="ACCOUNT">%2$s</xliff:g> (a User with this account already exists)?"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"Allow <xliff:g id="APP">%1$s</xliff:g> to create a new User with <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+    <string name="supervised_user_creation_label" msgid="6884904353827427515">"Add supervised user"</string>
     <string name="language_selection_title" msgid="52674936078683285">"Add a language"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"Region preference"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Type language name"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 7fada24..2108367 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -1989,6 +1989,7 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Custom app notification"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"Allow <xliff:g id="APP">%1$s</xliff:g> to create a new User with <xliff:g id="ACCOUNT">%2$s</xliff:g> (a User with this account already exists)?"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"Allow <xliff:g id="APP">%1$s</xliff:g> to create a new User with <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+    <string name="supervised_user_creation_label" msgid="6884904353827427515">"Add supervised user"</string>
     <string name="language_selection_title" msgid="52674936078683285">"Add a language"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"Region preference"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Type language name"</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index 0eaf8ef..68b1de3 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -1989,6 +1989,7 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‎‎‎‏‎‎‎‏‎‏‎‏‎‏‎‏‏‎‏‎‎‏‏‏‏‏‏‎‎‏‎‏‏‏‏‏‎‏‎‎‏‎‎‏‏‎‎‎‏‏‏‏‏‏‏‎Custom app notification‎‏‎‎‏‎"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‏‎‎‎‏‎‎‏‏‎‎‎‎‏‎‏‏‏‏‎‎‎‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‎‏‎‎‎‎‏‏‏‎‎‏‎‎‎‎‎‏‏‎Allow ‎‏‎‎‏‏‎<xliff:g id="APP">%1$s</xliff:g>‎‏‎‎‏‏‏‎ to create a new User with ‎‏‎‎‏‏‎<xliff:g id="ACCOUNT">%2$s</xliff:g>‎‏‎‎‏‏‏‎ (a User with this account already exists) ?‎‏‎‎‏‎"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‏‏‎‎‎‎‏‎‎‏‏‏‎‏‏‏‎‎‎‎‎‎‏‏‏‏‎‎‏‏‎‎‎‎‎‏‎‏‏‎‎‎‎‏‎‏‎‎‏‎‏‏‏‎‎‎Allow ‎‏‎‎‏‏‎<xliff:g id="APP">%1$s</xliff:g>‎‏‎‎‏‏‏‎ to create a new User with ‎‏‎‎‏‏‎<xliff:g id="ACCOUNT">%2$s</xliff:g>‎‏‎‎‏‏‏‎ ?‎‏‎‎‏‎"</string>
+    <string name="supervised_user_creation_label" msgid="6884904353827427515">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‏‏‎‎‎‏‏‎‎‎‎‎‏‏‎‎‎‎‎‎‎‏‎‎‎‎‎‏‏‎‎‏‎‎‏‏‎‏‏‎‎‏‎‎‏‎‏‎‎‏‎‏‏‏‎‏‏‎Add supervised user‎‏‎‎‏‎"</string>
     <string name="language_selection_title" msgid="52674936078683285">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‎‎‏‎‏‏‏‎‏‏‎‎‏‎‎‎‏‏‏‎‎‏‎‎‏‏‎‏‎‎‎‏‎‏‏‎‎‎‏‎‎‏‎‏‎‎‏‏‎‎‏‎‎‏‎‏‎‏‎Add a language‎‏‎‎‏‎"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‎‎‏‏‏‎‏‏‎‎‏‏‏‏‎‏‎‏‎‏‎‏‎‎‏‏‎‏‏‎‏‎‏‏‎‏‏‎‎‎‏‎‎‎‏‏‏‏‎‏‏‏‎‏‎‏‏‎Region preference‎‏‎‎‏‎"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‎‏‎‎‏‏‎‏‎‎‎‎‎‎‎‎‎‏‏‏‎‎‏‎‏‏‏‎‎‏‎‎‏‎‎‎‎‏‎‏‎‎‏‏‎‏‏‏‎‎‏‏‏‎‏‏‏‏‎Type language name‎‏‎‎‏‎"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 93a316f..517ee57 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -325,7 +325,7 @@
     <string name="permgrouplab_phone" msgid="570318944091926620">"Teléfono"</string>
     <string name="permgroupdesc_phone" msgid="270048070781478204">"hacer y administrar llamadas telefónicas"</string>
     <string name="permgrouplab_sensors" msgid="9134046949784064495">"Sensores corporales"</string>
-    <string name="permgroupdesc_sensors" msgid="2610631290633747752">"acceder a los datos del sensor acerca de tus signos vitales"</string>
+    <string name="permgroupdesc_sensors" msgid="2610631290633747752">"acceder a los datos de sensores acerca de tus signos vitales"</string>
     <string name="permgrouplab_notifications" msgid="5472972361980668884">"Notificaciones"</string>
     <string name="permgroupdesc_notifications" msgid="4608679556801506580">"mostrar notificaciones"</string>
     <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Recuperar el contenido de las ventanas"</string>
@@ -733,8 +733,8 @@
     <string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"Permite que el propietario inicie el uso de permisos para una app. No debería requerirse para apps normales."</string>
     <string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"iniciar vista de funciones de la app"</string>
     <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Permite que el propietario vea la información de las funciones de una app."</string>
-    <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"Acceder a los datos del sensor a una tasa de muestreo alta"</string>
-    <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Permite que la app tome una muestra de los datos del sensor a una tasa superior a 200 Hz"</string>
+    <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"Acceder a los datos de sensores a una tasa de muestreo alta"</string>
+    <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Permite que la app tome una muestra de los datos de sensores a una tasa superior a 200 Hz"</string>
     <string name="policylab_limitPassword" msgid="4851829918814422199">"Establecer reglas de contraseña"</string>
     <string name="policydesc_limitPassword" msgid="4105491021115793793">"Controlar la longitud y los caracteres permitidos en las contraseñas y los PIN para el bloqueo de pantalla."</string>
     <string name="policylab_watchLogin" msgid="7599669460083719504">"Supervisa los intentos para desbloquear la pantalla"</string>
@@ -1989,6 +1989,8 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Notificación de app personalizada"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"¿Quieres permitir que <xliff:g id="APP">%1$s</xliff:g> cree un usuario nuevo con <xliff:g id="ACCOUNT">%2$s</xliff:g>? (Ya existe un usuario con esta cuenta)"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"¿Deseas permitir que <xliff:g id="APP">%1$s</xliff:g> cree un usuario nuevo con <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+    <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+    <skip />
     <string name="language_selection_title" msgid="52674936078683285">"Agregar un idioma"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"Preferencia de región"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Nombre del idioma"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 22de5d1..b58d116 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1989,6 +1989,8 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Notificación de aplicación personalizada"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"¿Permitir que <xliff:g id="APP">%1$s</xliff:g> cree otro usuario con la cuenta <xliff:g id="ACCOUNT">%2$s</xliff:g>, que ya tiene uno?"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"¿Permitir que <xliff:g id="APP">%1$s</xliff:g> cree otro usuario con la cuenta <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+    <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+    <skip />
     <string name="language_selection_title" msgid="52674936078683285">"Añadir un idioma"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"Preferencia de región"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Nombre de idioma"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 334a666..3afe63dd 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -1989,6 +1989,8 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Rakenduse kohandatud märguanne"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"Kas lubada rakendusel <xliff:g id="APP">%1$s</xliff:g> luua uus kasutaja kontoga <xliff:g id="ACCOUNT">%2$s</xliff:g> (selle kontoga kasutaja on juba olemas)?"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"Kas lubada rakendusel <xliff:g id="APP">%1$s</xliff:g> luua uus kasutaja kontoga <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+    <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+    <skip />
     <string name="language_selection_title" msgid="52674936078683285">"Keele lisamine"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"Piirkonnaeelistus"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Sisestage keele nimi"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index df16b73..b4b4ec2 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -1989,6 +1989,7 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Aplikazio-jakinarazpen pertsonalizatua"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="ACCOUNT">%2$s</xliff:g> kontua duen erabiltzailea sortzeko baimena eman nahi diozu <xliff:g id="APP">%1$s</xliff:g> aplikazioari? (Badago kontu hori duen erabiltzaile bat)"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="ACCOUNT">%2$s</xliff:g> kontua duen erabiltzailea sortzeko baimena eman nahi diozu <xliff:g id="APP">%1$s</xliff:g> aplikazioari?"</string>
+    <string name="supervised_user_creation_label" msgid="6884904353827427515">"Gehitu gainbegiratutako erabiltzaile bat"</string>
     <string name="language_selection_title" msgid="52674936078683285">"Gehitu hizkuntza bat"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"Lurralde-hobespena"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Adierazi hizkuntza"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index e66c783..b8f2673 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -1989,6 +1989,8 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"اعلان برنامه سفارشی"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"به<xliff:g id="APP">%1$s</xliff:g> اجازه می‌دهید با <xliff:g id="ACCOUNT">%2$s</xliff:g> (کاربری با این حساب درحال‌حاضر وجود دارد) کاربری جدید ایجاد کند؟"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"به <xliff:g id="APP">%1$s</xliff:g> اجازه می‌دهید با <xliff:g id="ACCOUNT">%2$s</xliff:g> کاربری جدید ایجاد کند؟"</string>
+    <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+    <skip />
     <string name="language_selection_title" msgid="52674936078683285">"افزودن زبان"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"اولویت‌های منطقه"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"نام زبان را تایپ کنید"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index ff17fc1..618cd52 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -1989,6 +1989,8 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Oma sovellusilmoitus"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"Saako <xliff:g id="APP">%1$s</xliff:g> luoda uuden käyttäjän (<xliff:g id="ACCOUNT">%2$s</xliff:g>) – tällä käyttäjällä on jo tili?"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"Saako <xliff:g id="APP">%1$s</xliff:g> luoda uuden käyttäjän (<xliff:g id="ACCOUNT">%2$s</xliff:g>)?"</string>
+    <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+    <skip />
     <string name="language_selection_title" msgid="52674936078683285">"Lisää kieli"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"Alueasetus"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Anna kielen nimi"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index e367f32..4cc5c14 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -624,8 +624,7 @@
     <string name="face_recalibrate_notification_content" msgid="3064513770251355594">"Touchez pour supprimer votre modèle facial, puis ajoutez votre visage de nouveau"</string>
     <string name="face_setup_notification_title" msgid="8843461561970741790">"Configurer le déverrouillage par reconnaissance faciale"</string>
     <string name="face_setup_notification_content" msgid="5463999831057751676">"Déverrouillez votre téléphone en le regardant"</string>
-    <!-- no translation found for face_sensor_privacy_enabled (7407126963510598508) -->
-    <skip />
+    <string name="face_sensor_privacy_enabled" msgid="7407126963510598508">"Pour utiliser le déverrouillage par reconnaissance faciale, activez l\'"<b>"accès à l\'appareil photo"</b>" dans Paramètres &gt; Confidentialité"</string>
     <string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Configurer d\'autres méthodes de déverrouillage"</string>
     <string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Touchez pour ajouter une empreinte digitale"</string>
     <string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Déverrouillage par empreinte digitale"</string>
@@ -1990,6 +1989,8 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Notification d\'application personnalisée"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"Autoriser <xliff:g id="APP">%1$s</xliff:g> à créer un utilisateur <xliff:g id="ACCOUNT">%2$s</xliff:g>? (Un utilisateur est déjà associé à ce compte)"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"Autoriser <xliff:g id="APP">%1$s</xliff:g> à créer un profil d\'utilisateur avec le compte <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+    <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+    <skip />
     <string name="language_selection_title" msgid="52674936078683285">"Ajouter une langue"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"Préférences régionales"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Entrez la langue"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index e00304b..19adf8a 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -1989,6 +1989,8 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Notification d\'application personnalisée"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"Autoriser <xliff:g id="APP">%1$s</xliff:g> à créer un profil utilisateur avec le compte <xliff:g id="ACCOUNT">%2$s</xliff:g> (un utilisateur associé à ce compte existe déjà) ?"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"Autoriser <xliff:g id="APP">%1$s</xliff:g> à créer un profil utilisateur avec le compte <xliff:g id="ACCOUNT">%2$s</xliff:g> ?"</string>
+    <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+    <skip />
     <string name="language_selection_title" msgid="52674936078683285">"Ajouter une langue"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"Préférences régionales"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Saisissez la langue"</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 6f9ee8f..a61ef81 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -1989,6 +1989,7 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Notificación de aplicacións personalizada"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"Queres permitir que <xliff:g id="APP">%1$s</xliff:g> cree un usuario novo con <xliff:g id="ACCOUNT">%2$s</xliff:g>? (Xa existe un usuario con esta conta)"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"Queres permitir que <xliff:g id="APP">%1$s</xliff:g> cree un usuario novo con <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+    <string name="supervised_user_creation_label" msgid="6884904353827427515">"Engadir usuario supervisado"</string>
     <string name="language_selection_title" msgid="52674936078683285">"Engadir un idioma"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"Preferencia de rexión"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Escribe o nome do idioma"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 533d3fb..9971033 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -1989,6 +1989,8 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"ઍપનું કસ્ટમ નોટિફિકેશન"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="APP">%1$s</xliff:g>ને <xliff:g id="ACCOUNT">%2$s</xliff:g> માટે એક નવા વપરાશકર્તા બનાવવાની મંજૂરી આપીએ (આ એકાઉન્ટ માટે એક વપરાશકર્તા પહેલાંથી અસ્તિત્વમાં છે) ?"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="APP">%1$s</xliff:g>ને <xliff:g id="ACCOUNT">%2$s</xliff:g> માટે એક નવા વપરાશકર્તા બનાવવાની મંજૂરી આપીએ ?"</string>
+    <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+    <skip />
     <string name="language_selection_title" msgid="52674936078683285">"ભાષા ઉમેરો"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"પ્રદેશ પસંદગી"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"ભાષાનું નામ ટાઇપ કરો"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 8459437..a30c9a9 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1989,6 +1989,7 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"ऐप्लिकेशन की सूचना पसंद के मुताबिक बनाएं"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="APP">%1$s</xliff:g> को <xliff:g id="ACCOUNT">%2$s</xliff:g> के नाम से एक नया उपयोगकर्ता बनाने की अनुमति दें (इस नाम से एक खाता पहले से मौजूद है)?"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"Allow <xliff:g id="APP">%1$s</xliff:g> to create a new User with <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+    <string name="supervised_user_creation_label" msgid="6884904353827427515">"निगरानी में रखा गया उपयोगकर्ता जोड़ें"</string>
     <string name="language_selection_title" msgid="52674936078683285">"भाषा जोड़ें"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"क्षेत्र प्राथमिकता"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"भाषा का नाम लिखें"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 69905ec..6afc049 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -2021,6 +2021,7 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Prilagođena obavijest aplikacije"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"Dopustiti aplikaciji <xliff:g id="APP">%1$s</xliff:g> da izradi novog korisnika s računom <xliff:g id="ACCOUNT">%2$s</xliff:g> (korisnik s ovim računom već postoji)?"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"Dopustiti aplikaciji <xliff:g id="APP">%1$s</xliff:g> da izradi novog korisnika s računom <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+    <string name="supervised_user_creation_label" msgid="6884904353827427515">"Dodaj nadziranog korisnika"</string>
     <string name="language_selection_title" msgid="52674936078683285">"Dodavanje jezika"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"Postavke regije"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Unesite naziv jezika"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 4f04016..c736246 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -1989,6 +1989,7 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Egyéni alkalmazásértesítés"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"Engedélyezi a(z) <xliff:g id="APP">%1$s</xliff:g> számára, hogy új felhasználót hozzon létre a(z) <xliff:g id="ACCOUNT">%2$s</xliff:g> fiókkal? (Már létezik felhasználó ezzel a fiókkal.)"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"Engedélyezi a(z) <xliff:g id="APP">%1$s</xliff:g> számára, hogy új felhasználót hozzon létre a(z) <xliff:g id="ACCOUNT">%2$s</xliff:g> fiókkal?"</string>
+    <string name="supervised_user_creation_label" msgid="6884904353827427515">"Felügyelt felhasználó hozzáadása"</string>
     <string name="language_selection_title" msgid="52674936078683285">"Nyelv hozzáadása"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"Régió beállítása"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Adja meg a nyelvet"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 141780e..4f8f8e8 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -1989,6 +1989,7 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Հավելվածի հատուկ ծանուցում"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"Թույլատրե՞լ <xliff:g id="APP">%1$s</xliff:g> հավելվածին <xliff:g id="ACCOUNT">%2$s</xliff:g> հաշվով նոր Օգտատեր ստեղծել (նման հաշվով Օգտատեր արդեն գոյություն ունի):"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"Թույլատրե՞լ <xliff:g id="APP">%1$s</xliff:g> հավելվածին <xliff:g id="ACCOUNT">%2$s</xliff:g> հաշվով նոր Օգտատեր ստեղծել:"</string>
+    <string name="supervised_user_creation_label" msgid="6884904353827427515">"Ավելացնել վերահսկվող օգտատեր"</string>
     <string name="language_selection_title" msgid="52674936078683285">"Ավելացնել լեզու"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"Նախընտրելի տարածաշրջան"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Մուտքագրեք լեզուն"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index e1e8ea9..1457450 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -1989,6 +1989,8 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Notifikasi aplikasi kustom"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"Izinkan <xliff:g id="APP">%1$s</xliff:g> membuat Pengguna baru dengan <xliff:g id="ACCOUNT">%2$s</xliff:g> (Pengguna dengan akun ini sudah ada) ?"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"Izinkan <xliff:g id="APP">%1$s</xliff:g> membuat Pengguna baru dengan <xliff:g id="ACCOUNT">%2$s</xliff:g> ?"</string>
+    <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+    <skip />
     <string name="language_selection_title" msgid="52674936078683285">"Tambahkan bahasa"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"Preferensi wilayah"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Ketik nama bahasa"</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 0678ab2..cd28dc9 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -1989,6 +1989,8 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Sérsniðin forritatilkynning"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"Viltu leyfa <xliff:g id="APP">%1$s</xliff:g> að stofna nýjan notanda með <xliff:g id="ACCOUNT">%2$s</xliff:g> (notandi með þennan reikning er þegar fyrir hendi)?"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"Leyfa <xliff:g id="APP">%1$s</xliff:g> að stofna nýjan notanda með <xliff:g id="ACCOUNT">%2$s</xliff:g> ?"</string>
+    <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+    <skip />
     <string name="language_selection_title" msgid="52674936078683285">"Bæta við tungumáli"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"Svæðisval"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Sláðu inn heiti tungumáls"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index a63fbd8..6571f23 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -1989,6 +1989,7 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Notifica app personalizzata"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"Consentire a <xliff:g id="APP">%1$s</xliff:g> di creare un nuovo utente con l\'account <xliff:g id="ACCOUNT">%2$s</xliff:g> (esiste già un utente con questo account)?"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"Consentire a <xliff:g id="APP">%1$s</xliff:g> di creare un nuovo utente con l\'account <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+    <string name="supervised_user_creation_label" msgid="6884904353827427515">"Aggiungi utente supervisionato"</string>
     <string name="language_selection_title" msgid="52674936078683285">"Aggiungi una lingua"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"Area geografica preferita"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Digita nome lingua"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 7a594d8..4214bc2 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -2053,6 +2053,8 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"התראות אפליקציה בהתאמה אישית"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"האם לאפשר לאפליקציה <xliff:g id="APP">%1$s</xliff:g> ליצור משתמש חדש באמצעות <xliff:g id="ACCOUNT">%2$s</xliff:g> (כבר קיים משתמש לחשבון הזה)?"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"לאפשר לאפליקציה <xliff:g id="APP">%1$s</xliff:g> ליצור משתמש חדש באמצעות <xliff:g id="ACCOUNT">%2$s</xliff:g> ?"</string>
+    <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+    <skip />
     <string name="language_selection_title" msgid="52674936078683285">"הוספת שפה"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"העדפת אזור"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"יש להקליד את שם השפה"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 241105f..7a6b566 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -1989,6 +1989,7 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"カスタムアプリ通知"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="APP">%1$s</xliff:g> が <xliff:g id="ACCOUNT">%2$s</xliff:g> で新しいユーザーを作成できるようにしますか?(このアカウントのユーザーはすでに存在します)"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="APP">%1$s</xliff:g> が <xliff:g id="ACCOUNT">%2$s</xliff:g> で新しいユーザーを作成できるようにしますか?"</string>
+    <string name="supervised_user_creation_label" msgid="6884904353827427515">"監視対象ユーザーを追加"</string>
     <string name="language_selection_title" msgid="52674936078683285">"言語を追加"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"地域設定"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"言語名を入力"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 2137e0f..6ab9312 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -1989,6 +1989,7 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"აპის მორგებული შეტყობინება"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"მიეცეს უფლება <xliff:g id="APP">%1$s</xliff:g>-ს <xliff:g id="ACCOUNT">%2$s</xliff:g>-ის მეშვეობით ახალი მომხმარებელი შექმნას (ამ ანგარიშის მქონე მომხმარებელი უკვე არსებობს)?"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"მიეცეს უფლება <xliff:g id="APP">%1$s</xliff:g>-ს <xliff:g id="ACCOUNT">%2$s</xliff:g>-ის მეშვეობით ახალი მომხმარებელი შექმნას?"</string>
+    <string name="supervised_user_creation_label" msgid="6884904353827427515">"კონტროლის ქვეშ მყოფი მომხმარებლის დამატება"</string>
     <string name="language_selection_title" msgid="52674936078683285">"ენის დამატება"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"რეგიონის პარამეტრები"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"აკრიფეთ ენის სახელი"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 3042c64..b231be1 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -1989,6 +1989,8 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Арнаулы хабар хабарландыруы"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="APP">%1$s</xliff:g> қолданбасына <xliff:g id="ACCOUNT">%2$s</xliff:g> аккаунты бар жаңа пайдаланушы (мұндай аккаунтқа ие пайдаланушы бұрыннан бар) жасауға рұқсат етілсін бе?"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="APP">%1$s</xliff:g> қолданбасына <xliff:g id="ACCOUNT">%2$s</xliff:g> аккаунты бар жаңа пайдаланушы жасауға рұқсат етілсін бе?"</string>
+    <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+    <skip />
     <string name="language_selection_title" msgid="52674936078683285">"Тіл қосу"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"Аймақ параметрі"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Тіл атауын теріңіз"</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 81fbca5..6d72625 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -1989,6 +1989,7 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"ការជូន​ដំណឹងកម្មវិធី​ផ្ទាល់ខ្លួន"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"អនុញ្ញាតឱ្យ <xliff:g id="APP">%1$s</xliff:g> បង្កើតអ្នកប្រើប្រាស់​ថ្មីដោយប្រើ <xliff:g id="ACCOUNT">%2$s</xliff:g> (អ្នកប្រើប្រាស់ដែលមានគណនីនេះមានរួចហើយ) ដែរឬទេ?"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"អនុញ្ញាតឱ្យ <xliff:g id="APP">%1$s</xliff:g> បង្កើតអ្នកប្រើប្រាស់​ថ្មីដោយប្រើ <xliff:g id="ACCOUNT">%2$s</xliff:g> ដែរឬទេ?"</string>
+    <string name="supervised_user_creation_label" msgid="6884904353827427515">"បញ្ចូលអ្នកប្រើប្រាស់ដែលស្ថិតក្រោមការគ្រប់គ្រង"</string>
     <string name="language_selection_title" msgid="52674936078683285">"បន្ថែមភាសា"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"ចំណូលចិត្តតំបន់"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"វាយបញ្ចូលឈ្មោះភាសា"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 569f6a5..5ec2013 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -1989,6 +1989,8 @@
     <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>
     <string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="ACCOUNT">%2$s</xliff:g> ಮೂಲಕ ಹೊಸ ಬಳಕೆದಾರರನ್ನು ರಚಿಸಲು <xliff:g id="APP">%1$s</xliff:g> ಗೆ ಅನುಮತಿಸುವುದೇ ?"</string>
+    <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+    <skip />
     <string name="language_selection_title" msgid="52674936078683285">"ಭಾಷೆ ಸೇರಿಸಿ"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"ಪ್ರದೇಶ ಪ್ರಾಶಸ್ತ್ಯ"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"ಭಾಷೆ ಹೆಸರನ್ನು ಟೈಪ್ ಮಾಡಿ"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 01d040f..3b58e62 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1989,6 +1989,8 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"맞춤 앱 알림"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="APP">%1$s</xliff:g>에서 <xliff:g id="ACCOUNT">%2$s</xliff:g> 계정으로 신규 사용자를 만들도록 허용하시겠습니까? 이 계정으로 등록된 사용자가 이미 존재합니다."</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="APP">%1$s</xliff:g>에서 <xliff:g id="ACCOUNT">%2$s</xliff:g> 계정으로 신규 사용자를 만들도록 허용하시겠습니까?"</string>
+    <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+    <skip />
     <string name="language_selection_title" msgid="52674936078683285">"언어 추가"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"지역 환경설정"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"언어 이름 입력"</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index e153773..ab2ab9b 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -1989,6 +1989,7 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Колдонмонун ыңгайлаштырылган билдирмеси"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="APP">%1$s</xliff:g> колдонмосуна <xliff:g id="ACCOUNT">%2$s</xliff:g> аккаунту менен жаңы колдонуучу түзүүгө уруксат бересизби (мындай аккаунту бар колдонуучу мурунтан эле бар)?"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="APP">%1$s</xliff:g> колдонмосуна <xliff:g id="ACCOUNT">%2$s</xliff:g> аккаунту менен жаңы колдонуучу түзүүгө уруксат бересизби?"</string>
+    <string name="supervised_user_creation_label" msgid="6884904353827427515">"Көзөмөлдөнгөн колдонуучуну кошуу"</string>
     <string name="language_selection_title" msgid="52674936078683285">"Тил кошуу"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"Чөлкөмдүк жөндөөлөр"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Тилди киргизиңиз"</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index b3cb5af..2018524 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -1989,6 +1989,8 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"ການແຈ້ງເຕືອນແອັບແບບກຳນົດເອງ"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"ອະນຸຍາດໃຫ້ <xliff:g id="APP">%1$s</xliff:g> ສ້າງຜູ້ໃຊ້ໃໝ່ກັບ <xliff:g id="ACCOUNT">%2$s</xliff:g> ໄດ້ບໍ່ (ມີຜູ້ໃຊ້ທີ່ໃຊ້ບັນຊີນີ້ຢູ່ກ່ອນແລ້ວ) ?"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"ອະນຸຍາດໃຫ້ <xliff:g id="APP">%1$s</xliff:g> ສ້າງຜູ້ໃຊ້ໃໝ່ກັບ <xliff:g id="ACCOUNT">%2$s</xliff:g> ໄດ້ບໍ?"</string>
+    <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+    <skip />
     <string name="language_selection_title" msgid="52674936078683285">"ເພີ່ມພາສາ"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"ການຕັ້ງຄ່າພາກພື້ນ"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"ພິມຊື່ພາສາ"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 70f0f42..aea67f2 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -2053,6 +2053,7 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Tinkintas programos pranešimas"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"Leisti „<xliff:g id="APP">%1$s</xliff:g>“ kurti naują <xliff:g id="ACCOUNT">%2$s</xliff:g> naudotoją (šią paskyrą naudojantis naudotojas jau yra)?"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"Leisti „<xliff:g id="APP">%1$s</xliff:g>“ kurti naują <xliff:g id="ACCOUNT">%2$s</xliff:g> naudotoją?"</string>
+    <string name="supervised_user_creation_label" msgid="6884904353827427515">"Pridėti prižiūrimą naudotoją"</string>
     <string name="language_selection_title" msgid="52674936078683285">"Pridėkite kalbą"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"Regiono nuostata"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Įveskite kalbos pav."</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 1df7774..495bc38 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -2021,6 +2021,8 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Pielāgots lietotnes paziņojums"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"Vai atļaut lietotnei <xliff:g id="APP">%1$s</xliff:g> izveidot jaunu lietotāju, izmantojot e-pasta adresi <xliff:g id="ACCOUNT">%2$s</xliff:g> (lietotājs ar šādu kontu jau pastāv)?"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"Vai atļaut lietotnei <xliff:g id="APP">%1$s</xliff:g> izveidot jaunu lietotāju, izmantojot e-pasta adresi <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+    <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+    <skip />
     <string name="language_selection_title" msgid="52674936078683285">"Pievienot valodu"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"Reģiona preference"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Ierakstiet valodas nosaukumu"</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index cc86005..92e1d5f 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -1989,6 +1989,7 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Приспособено известување за апликација"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"Дозволувате <xliff:g id="APP">%1$s</xliff:g> да создаде нов корисник со <xliff:g id="ACCOUNT">%2$s</xliff:g>? (Веќе постои корисник со оваа сметка.)"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"Дозволувате <xliff:g id="APP">%1$s</xliff:g> да создаде нов корисник со <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+    <string name="supervised_user_creation_label" msgid="6884904353827427515">"Додајте надгледуван корисник"</string>
     <string name="language_selection_title" msgid="52674936078683285">"Додајте јазик"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"Претпочитувања за регион"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Внесете име на јазик"</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index 2517704..0d76eae 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -1989,6 +1989,7 @@
     <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>
     <string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="ACCOUNT">%2$s</xliff:g> എന്ന അക്കൗണ്ട് ഉപയോഗിച്ച് പുതിയ ഉപയോക്താവിനെ സൃഷ്‌ടിക്കാൻ <xliff:g id="APP">%1$s</xliff:g> എന്നതിനെ അനുവദിക്കണോ?"</string>
+    <string name="supervised_user_creation_label" msgid="6884904353827427515">"മേൽനോട്ടത്തിലുള്ള ഉപയോക്താവിനെ ചേർക്കൂ"</string>
     <string name="language_selection_title" msgid="52674936078683285">"ഒരു ഭാഷ ചേർക്കുക"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"മേഖലാ മുൻഗണന"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"ഭാഷ ടൈപ്പ് ചെയ്യുക"</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 6be8243..24cad85 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -1989,6 +1989,7 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Аппын захиалгат мэдэгдэл"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="APP">%1$s</xliff:g>-д <xliff:g id="ACCOUNT">%2$s</xliff:g>-тай (ийм бүртгэлтэй хэрэглэгч аль хэдийн байна) шинэ хэрэглэгч үүсгэхийг зөвшөөрөх үү ?"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="APP">%1$s</xliff:g>-д <xliff:g id="ACCOUNT">%2$s</xliff:g>-тай шинэ хэрэглэгч үүсгэхийг зөвшөөрөх үү?"</string>
+    <string name="supervised_user_creation_label" msgid="6884904353827427515">"Хяналттай хэрэглэгч нэмэх"</string>
     <string name="language_selection_title" msgid="52674936078683285">"Хэл нэмэх"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"Бүс нутгийн тохиргоо"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Улсын хэлийг бичнэ үү"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index 69279ee..162b4ae 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -1989,6 +1989,7 @@
     <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>
     <string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="ACCOUNT">%2$s</xliff:g> सह नवीन वापरकर्ता तयार करण्याची <xliff:g id="APP">%1$s</xliff:g> ला अनुमती द्यायची आहे का?"</string>
+    <string name="supervised_user_creation_label" msgid="6884904353827427515">"व्यवस्थापित वापरकर्ता जोडा"</string>
     <string name="language_selection_title" msgid="52674936078683285">"एक भाषा जोडा"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"प्रदेश प्राधान्य"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"भाषा नाव टाइप करा"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 27aac1a..4a50bc9 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -1989,6 +1989,8 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Pemberitahuan apl tersuai"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"Benarkan <xliff:g id="APP">%1$s</xliff:g> membuat Pengguna baharu dengan <xliff:g id="ACCOUNT">%2$s</xliff:g> (Pengguna dengan akaun ini sudah wujud) ?"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"Benarkan <xliff:g id="APP">%1$s</xliff:g> membuat Pengguna baharu dengan <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+    <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+    <skip />
     <string name="language_selection_title" msgid="52674936078683285">"Tambahkan bahasa"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"Pilihan wilayah"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Taipkan nama bahasa"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index eefbe15..169c0fd 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -1989,6 +1989,8 @@
     <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>
     <string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="ACCOUNT">%2$s</xliff:g> ဖြင့်အသုံးပြုသူအသစ်ကို <xliff:g id="APP">%1$s</xliff:g> အား ဖန်တီးခွင့်ပြုလိုပါသလား ။"</string>
+    <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+    <skip />
     <string name="language_selection_title" msgid="52674936078683285">"ဘာသာစကားတစ်ခု ထည့်ပါ"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"ဒေသရွေးချယ်မှု"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"ဘာသာစကားအမည် ထည့်ပါ"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 4d8d2b0..7c5ae01 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -1989,6 +1989,8 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Tilpasset appvarsel"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"Vil du la <xliff:g id="APP">%1$s</xliff:g> opprette en ny bruker med <xliff:g id="ACCOUNT">%2$s</xliff:g> (en bruker med denne kontoen eksisterer allerede)?"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"Vil du la <xliff:g id="APP">%1$s</xliff:g> opprette en ny bruker med <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+    <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+    <skip />
     <string name="language_selection_title" msgid="52674936078683285">"Legg til et språk"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"Regionsinnstilling"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Skriv inn språknavn"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 12c4464..7f9a832 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -1989,6 +1989,7 @@
     <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>
     <string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="ACCOUNT">%2$s</xliff:g> मा नयाँ प्रयोगकर्ता सिर्जना गर्न <xliff:g id="APP">%1$s</xliff:g> लाई अनुमति दिने हो?"</string>
+    <string name="supervised_user_creation_label" msgid="6884904353827427515">"सुपरिवेक्षित प्रयोगकर्ता हाल्नुहोस्"</string>
     <string name="language_selection_title" msgid="52674936078683285">"भाषा थप्नुहोस्"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"क्षेत्रको प्राथमिकता"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"भाषाको नाम टाइप गर्नुहोस्"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 858ca00..5dcdda4 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -37,7 +37,7 @@
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"Kan instellingen voor doorschakelen van gesprekken niet wijzigen vanaf je telefoon tijdens roaming."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"Service staat aan."</string>
     <string name="serviceEnabledFor" msgid="1463104778656711613">"Service staat aan voor:"</string>
-    <string name="serviceDisabled" msgid="641878791205871379">"Service staat uit."</string>
+    <string name="serviceDisabled" msgid="641878791205871379">"Service is uitgezet."</string>
     <string name="serviceRegistered" msgid="3856192211729577482">"De registratie is voltooid."</string>
     <string name="serviceErased" msgid="997354043770513494">"Wissen uitgevoerd."</string>
     <string name="passwordIncorrect" msgid="917087532676155877">"Onjuist wachtwoord."</string>
@@ -1733,7 +1733,7 @@
     <string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Tik op een functie om deze te gebruiken:"</string>
     <string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Functies kiezen voor gebruik met de knop Toegankelijkheid"</string>
     <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Functies kiezen voor gebruik met de sneltoets via de volumeknop"</string>
-    <string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"<xliff:g id="SERVICE_NAME">%s</xliff:g> staat uit"</string>
+    <string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"<xliff:g id="SERVICE_NAME">%s</xliff:g> is uitgezet"</string>
     <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Snelkoppelingen bewerken"</string>
     <string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"Klaar"</string>
     <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Sneltoets uitzetten"</string>
@@ -1989,6 +1989,7 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Aangepaste app-melding"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"Toestaan dat <xliff:g id="APP">%1$s</xliff:g> een nieuwe gebruiker met <xliff:g id="ACCOUNT">%2$s</xliff:g> maakt (er is al een gebruiker met dit account)?"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"Toestaan dat <xliff:g id="APP">%1$s</xliff:g> een nieuwe gebruiker met <xliff:g id="ACCOUNT">%2$s</xliff:g> maakt?"</string>
+    <string name="supervised_user_creation_label" msgid="6884904353827427515">"Gebr. met beperkte rechten maken"</string>
     <string name="language_selection_title" msgid="52674936078683285">"Taal toevoegen"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"Regiovoorkeur"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Typ de naam van een taal"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index 52015c2..919d193 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -1989,6 +1989,8 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"କଷ୍ଟମ୍ ଆପ୍ ବିଜ୍ଞପ୍ତି"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="APP">%1$s</xliff:g>ରେ ଏକ ନୂଆ ଉପଯୋଗକର୍ତ୍ତା ତିଆରି କରିବା ପାଇଁ <xliff:g id="ACCOUNT">%2$s</xliff:g>କୁ (ପୂର୍ବରୁ ଏହି ଆକାଉଣ୍ଟ ଉପଯୋଗକର୍ତ୍ତାଙ୍କ ନାମରେ ଅଛି) ଅନୁମତି ଦେବେ?"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="APP">%1$s</xliff:g>ରେ ଏକ ନୂଆ ଉପଯୋଗକର୍ତ୍ତା ତିଆରି କରିବା ପାଇଁ <xliff:g id="ACCOUNT">%2$s</xliff:g>କୁ ଅନୁମତି ଦେବେ?"</string>
+    <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+    <skip />
     <string name="language_selection_title" msgid="52674936078683285">"ଏକ ଭାଷା ଯୋଗ କରନ୍ତୁ"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"ପସନ୍ଦର ଅଞ୍ଚଳ"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"ଭାଷାର ନାମ ଟାଇପ୍‍ କରନ୍ତୁ"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 6826a2d..c628f1f 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -1989,6 +1989,7 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"ਵਿਉਂਤੀ ਐਪ ਸੂਚਨਾ"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"ਕੀ <xliff:g id="APP">%1$s</xliff:g> ਨੂੰ <xliff:g id="ACCOUNT">%2$s</xliff:g> ਨਾਲ ਨਵਾਂ ਵਰਤੋਂਕਾਰ ਬਣਾਉਣ ਦੀ ਇਜਾਜ਼ਤ ਦੇਣੀ ਹੈ (ਇਸ ਖਾਤੇ ਨਾਲ ਇੱਕ ਵਰਤੋਂਕਾਰ ਪਹਿਲਾਂ ਤੋਂ ਹੀ ਮੌਜੂਦ ਹੈ)?"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"ਕੀ <xliff:g id="APP">%1$s</xliff:g> ਨੂੰ <xliff:g id="ACCOUNT">%2$s</xliff:g> ਨਾਲ ਨਵਾਂ ਵਰਤੋਂਕਾਰ ਬਣਾਉਣ ਦੀ ਇਜਾਜ਼ਤ ਦੇਣੀ ਹੈ?"</string>
+    <string name="supervised_user_creation_label" msgid="6884904353827427515">"ਨਿਗਰਾਨੀ ਕੀਤਾ ਵਰਤੋਂਕਾਰ ਸ਼ਾਮਲ ਕਰੋ"</string>
     <string name="language_selection_title" msgid="52674936078683285">"ਇੱਕ ਭਾਸ਼ਾ ਸ਼ਾਮਲ ਕਰੋ"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"ਖੇਤਰ ਤਰਜੀਹ"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"ਭਾਸ਼ਾ ਦਾ ਨਾਮ ਟਾਈਪ ਕਰੋ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index e16d2af..6689a1a 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -2053,6 +2053,8 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Niestandardowe powiadomienie z aplikacji"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"Zezwolić aplikacji <xliff:g id="APP">%1$s</xliff:g> na utworzenie nowego użytkownika dla konta <xliff:g id="ACCOUNT">%2$s</xliff:g> (użytkownik dla tego konta już istnieje)?"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"Zezwolić aplikacji <xliff:g id="APP">%1$s</xliff:g> na utworzenie nowego użytkownika dla konta <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+    <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+    <skip />
     <string name="language_selection_title" msgid="52674936078683285">"Dodaj język"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"Ustawienie regionu"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Wpisz nazwę języka"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 52d7992..e2bd6c5 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -1989,6 +1989,7 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Notificação personalizada do app"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"Permitir que o app <xliff:g id="APP">%1$s</xliff:g> crie um novo usuário com <xliff:g id="ACCOUNT">%2$s</xliff:g> (já existe um usuário com essa conta)?"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"Permitir que o app <xliff:g id="APP">%1$s</xliff:g> crie um novo usuário com <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+    <string name="supervised_user_creation_label" msgid="6884904353827427515">"Adicionar usuário supervisionado"</string>
     <string name="language_selection_title" msgid="52674936078683285">"Adicionar um idioma"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"Preferência de região"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Digitar nome do idioma"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 2ea9f39..1daf451 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -1989,6 +1989,8 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Notificação de app personalizada"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"Permitir que a app <xliff:g id="APP">%1$s</xliff:g> crie um novo utilizador com a conta <xliff:g id="ACCOUNT">%2$s</xliff:g> (já existe um utilizador com esta conta)?"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"Permitir que a app <xliff:g id="APP">%1$s</xliff:g> crie um novo utilizador com a conta <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+    <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+    <skip />
     <string name="language_selection_title" msgid="52674936078683285">"Adicionar um idioma"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"Preferência de região"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Intr. nome do idioma"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 52d7992..e2bd6c5 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -1989,6 +1989,7 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Notificação personalizada do app"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"Permitir que o app <xliff:g id="APP">%1$s</xliff:g> crie um novo usuário com <xliff:g id="ACCOUNT">%2$s</xliff:g> (já existe um usuário com essa conta)?"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"Permitir que o app <xliff:g id="APP">%1$s</xliff:g> crie um novo usuário com <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+    <string name="supervised_user_creation_label" msgid="6884904353827427515">"Adicionar usuário supervisionado"</string>
     <string name="language_selection_title" msgid="52674936078683285">"Adicionar um idioma"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"Preferência de região"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Digitar nome do idioma"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index ac5eca7..035d1eb 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -2021,6 +2021,7 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Notificare de aplicație personalizată"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"Permiteți ca <xliff:g id="APP">%1$s</xliff:g> să creeze un nou utilizator folosind <xliff:g id="ACCOUNT">%2$s</xliff:g>? (există deja un utilizator cu acest cont)"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"Permiteți ca <xliff:g id="APP">%1$s</xliff:g> să creeze un nou utilizator folosind <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+    <string name="supervised_user_creation_label" msgid="6884904353827427515">"Adăugați un utilizator monitorizat"</string>
     <string name="language_selection_title" msgid="52674936078683285">"Adăugați o limbă"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"Regiunea preferată"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Numele limbii"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 6182832..1b64a3b 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -2053,6 +2053,8 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Уведомление пользовательского приложения"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"Разрешить приложению \"<xliff:g id="APP">%1$s</xliff:g>\" создать нового пользователя с аккаунтом <xliff:g id="ACCOUNT">%2$s</xliff:g> (пользователь с этим аккаунтом уже существует)?"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"Разрешить приложению \"<xliff:g id="APP">%1$s</xliff:g>\" создать нового пользователя с аккаунтом <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+    <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+    <skip />
     <string name="language_selection_title" msgid="52674936078683285">"Добавить язык"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"Региональные настройки"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Введите название языка"</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index c5e76c8..cf7fc87 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -1989,6 +1989,8 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"අභිරුචි යෙදුම් දැනුම් දීම"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="APP">%1$s</xliff:g> හට <xliff:g id="ACCOUNT">%2$s</xliff:g> සමගින් නව පරිශීලකයෙකු සෑදීමට ඉඩ දෙන්නද (මෙම ගිණුම සහිත පරිශීලකයෙකු දැනටමත් සිටී) ?"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="APP">%1$s</xliff:g> හට <xliff:g id="ACCOUNT">%2$s</xliff:g> සමගින් නව පරිශීලකයෙකු සෑදීමට ඉඩ දෙන්නද ?"</string>
+    <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+    <skip />
     <string name="language_selection_title" msgid="52674936078683285">"භාෂාවක් එක් කරන්න"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"ප්‍රදේශ මනාපය"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"භාෂා නම ටයිප් කරන්න"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index dfd34e7..c6423dc 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -2053,6 +2053,8 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Vlastné upozornenie na aplikáciu"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"Chcete povoliť aplikácii <xliff:g id="APP">%1$s</xliff:g> vytvoriť nového používateľa pomocou účtu <xliff:g id="ACCOUNT">%2$s</xliff:g> (používateľ s týmto účtom už existuje)?"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"Chcete povoliť aplikácii <xliff:g id="APP">%1$s</xliff:g> vytvoriť nového používateľa pomocou účtu <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+    <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+    <skip />
     <string name="language_selection_title" msgid="52674936078683285">"Pridať jazyk"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"Preferovaný región"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Zadajte názov jazyka"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 931fc5b..1e8f264 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -2053,6 +2053,7 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Obvestilo po meri iz aplikacije"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"Ali aplikaciji <xliff:g id="APP">%1$s</xliff:g> dovolite, da ustvari novega uporabnika za račun <xliff:g id="ACCOUNT">%2$s</xliff:g> (uporabnik s tem računom že obstaja)?"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"Ali aplikaciji <xliff:g id="APP">%1$s</xliff:g> dovolite, da ustvari novega uporabnika za račun <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+    <string name="supervised_user_creation_label" msgid="6884904353827427515">"Dodaj nadzorovanega uporabnika"</string>
     <string name="language_selection_title" msgid="52674936078683285">"Dodajanje jezika"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"Nastavitev območja"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Vnesite ime jezika"</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 937332b..705e309 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -1989,6 +1989,8 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Njoftim i personalizuar për aplikacionin"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"Të lejohet <xliff:g id="APP">%1$s</xliff:g> që të krijojë një përdorues të ri me <xliff:g id="ACCOUNT">%2$s</xliff:g> (një përdorues me këtë llogari ekziston tashmë) ?"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"Të lejohet <xliff:g id="APP">%1$s</xliff:g> që të krijojë një përdorues të ri me <xliff:g id="ACCOUNT">%2$s</xliff:g> ?"</string>
+    <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+    <skip />
     <string name="language_selection_title" msgid="52674936078683285">"Shto një gjuhë"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"Preferenca e rajonit"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Shkruaj emrin e gjuhës"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 72fd908..dde0e33 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -2021,6 +2021,7 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Прилагођено обавештење о апликацији"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"Желите ли да дозволите да <xliff:g id="APP">%1$s</xliff:g> направи новог корисника са налогом <xliff:g id="ACCOUNT">%2$s</xliff:g> (корисник са тим налогом већ постоји)?"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"Желите ли да дозволите да <xliff:g id="APP">%1$s</xliff:g> направи новог корисника са налогом <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+    <string name="supervised_user_creation_label" msgid="6884904353827427515">"Додајте корисника под надзором"</string>
     <string name="language_selection_title" msgid="52674936078683285">"Додајте језик"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"Подешавање региона"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Унесите назив језика"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index e078da0..2003e64 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -1989,6 +1989,7 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Anpassad appavisering"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"Tillåter du att <xliff:g id="APP">%1$s</xliff:g> skapar en ny användare för <xliff:g id="ACCOUNT">%2$s</xliff:g> (det finns redan en användare med det här kontot)?"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"Tillåter du att <xliff:g id="APP">%1$s</xliff:g> skapar en ny användare för <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+    <string name="supervised_user_creation_label" msgid="6884904353827427515">"Lägg till en kontrollerad användare"</string>
     <string name="language_selection_title" msgid="52674936078683285">"Lägg till ett språk"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"Regionsinställningar"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Ange språk"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 99fd107..f955203 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -1989,6 +1989,7 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Arifa ya programu maalum"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"Ruhusu <xliff:g id="APP">%1$s</xliff:g> iweke Mtumiaji mpya ikitumia <xliff:g id="ACCOUNT">%2$s</xliff:g> (Je, tayari kuna mtumiaji anayetumia akaunti hii)?"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"Ungependa kuruhusu <xliff:g id="APP">%1$s</xliff:g> iweke Mtumiaji mpya ikitumia <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+    <string name="supervised_user_creation_label" msgid="6884904353827427515">"Weka mtumiaji anayesimamiwa"</string>
     <string name="language_selection_title" msgid="52674936078683285">"Ongeza lugha"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"Mapendeleo ya eneo"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Weka jina la lugha"</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 0be25cd..a7296dc 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -170,7 +170,7 @@
     <string name="httpErrorFailedSslHandshake" msgid="546319061228876290">"பாதுகாப்பான இணைப்பை நிறுவ முடியவில்லை."</string>
     <string name="httpErrorBadUrl" msgid="754447723314832538">"URL தவறாக உள்ளதால் பக்கத்தைத் திறக்க முடியவில்லை."</string>
     <string name="httpErrorFile" msgid="3400658466057744084">"ஃபைலை அணுக முடியவில்லை."</string>
-    <string name="httpErrorFileNotFound" msgid="5191433324871147386">"கோரப்பட்ட கோப்பைக் கண்டறிய முடியவில்லை."</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>
     <string name="contentServiceSync" msgid="2341041749565687871">"ஒத்திசை"</string>
@@ -1526,8 +1526,8 @@
     <string name="vpn_lockdown_disconnected" msgid="5573611651300764955">"எப்போதும் இயக்கத்தில் இருக்கும்படி அமைத்த VPN இலிருந்து துண்டிக்கப்பட்டது"</string>
     <string name="vpn_lockdown_error" msgid="4453048646854247947">"எப்போதும் ஆனில் இருக்கும்படி அமைத்த VPN உடன் இணைக்க முடியவில்லை"</string>
     <string name="vpn_lockdown_config" msgid="8331697329868252169">"நெட்வொர்க் அல்லது VPN அமைப்புகளை மாற்றவும்"</string>
-    <string name="upload_file" msgid="8651942222301634271">"கோப்பைத் தேர்வுசெய்"</string>
-    <string name="no_file_chosen" msgid="4146295695162318057">"எந்தக் கோப்பும் தேர்வுசெய்யப்படவில்லை"</string>
+    <string name="upload_file" msgid="8651942222301634271">"ஃபலைத் தேர்வுசெய்"</string>
+    <string name="no_file_chosen" msgid="4146295695162318057">"எந்த ஃபைலும் தேர்வுசெய்யப்படவில்லை"</string>
     <string name="reset" msgid="3865826612628171429">"மீட்டமை"</string>
     <string name="submit" msgid="862795280643405865">"சமர்ப்பி"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"\'வாகனம் ஓட்டும் பயன்முறை’ ஆனில் உள்ளது"</string>
@@ -1989,6 +1989,7 @@
     <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>
     <string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="ACCOUNT">%2$s</xliff:g> மூலம் புதிய பயனரை உருவாக்க <xliff:g id="APP">%1$s</xliff:g> ஆப்ஸை அனுமதிக்கவா?"</string>
+    <string name="supervised_user_creation_label" msgid="6884904353827427515">"மேற்பார்வையிடப்படும் பயனரைச் சேர்"</string>
     <string name="language_selection_title" msgid="52674936078683285">"மொழியைச் சேர்"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"மண்டல விருப்பம்"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"மொழி பெயரை உள்ளிடுக"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 3aa7b04..dc21719 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -1989,6 +1989,7 @@
     <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>
     <string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="ACCOUNT">%2$s</xliff:g>తో కొత్త వినియోగదారుని సృష్టించడానికి <xliff:g id="APP">%1$s</xliff:g>ను అనుమతించాలా?"</string>
+    <string name="supervised_user_creation_label" msgid="6884904353827427515">"పర్యవేక్షించబడే యూజర్‌ను జోడించండి"</string>
     <string name="language_selection_title" msgid="52674936078683285">"భాషను జోడించండి"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"ప్రాంతం ప్రాధాన్యత"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"భాష పేరును టైప్ చేయండి"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 41adb26..15d7f30 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -1989,6 +1989,7 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"การแจ้งเตือนที่กำหนดเองของแอป"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"อนุญาตให้ <xliff:g id="APP">%1$s</xliff:g> สร้างผู้ใช้ใหม่ด้วย <xliff:g id="ACCOUNT">%2$s</xliff:g> ไหม (มีผู้ใช้ที่มีบัญชีนี้อยู่แล้ว)"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"อนุญาตให้ <xliff:g id="APP">%1$s</xliff:g> สร้างผู้ใช้ใหม่ด้วย <xliff:g id="ACCOUNT">%2$s</xliff:g> ไหม"</string>
+    <string name="supervised_user_creation_label" msgid="6884904353827427515">"เพิ่มผู้ใช้ภายใต้การควบคุมดูแล"</string>
     <string name="language_selection_title" msgid="52674936078683285">"เพิ่มภาษา"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"ค่ากำหนดภูมิภาค"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"พิมพ์ชื่อภาษา"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 7f39769..cb6c485 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -1989,6 +1989,8 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Custom na notification ng app"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"Payagan ang <xliff:g id="APP">%1$s</xliff:g> na gumawa ng bagong User sa <xliff:g id="ACCOUNT">%2$s</xliff:g> (mayroon nang User sa account na ito) ?"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"Payagan ang <xliff:g id="APP">%1$s</xliff:g> na gumawa ng bagong User sa <xliff:g id="ACCOUNT">%2$s</xliff:g> ?"</string>
+    <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+    <skip />
     <string name="language_selection_title" msgid="52674936078683285">"Magdagdag ng wika"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"Kagustuhan sa rehiyon"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"I-type ang wika"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index bc26fed..df4a960 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -1989,6 +1989,8 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Özel uygulama bildirimi"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="APP">%1$s</xliff:g> uygulamasının <xliff:g id="ACCOUNT">%2$s</xliff:g> hesabına sahip yeni bir Kullanıcı eklemesine izin verilsin mi (bu hesaba sahip bir kullanıcı zaten var)?"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="APP">%1$s</xliff:g> uygulamasının <xliff:g id="ACCOUNT">%2$s</xliff:g> hesabına sahip yeni bir Kullanıcı eklemesine izin verilsin mi?"</string>
+    <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+    <skip />
     <string name="language_selection_title" msgid="52674936078683285">"Dil ekleyin"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"Bölge tercihi"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Dil adını yazın"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 5ce1407..0539beba 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -2053,6 +2053,8 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Користувацьке сповіщення додатка"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"Дозволити додатку <xliff:g id="APP">%1$s</xliff:g> створити нового користувача з обліковим записом <xliff:g id="ACCOUNT">%2$s</xliff:g> (користувач із таким обліковим записом уже існує)?"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"Дозволити додатку <xliff:g id="APP">%1$s</xliff:g> створити нового користувача з обліковим записом <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+    <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+    <skip />
     <string name="language_selection_title" msgid="52674936078683285">"Додати мову"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"Вибір регіону"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Введіть назву мови"</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 7ceaa99..9d3c357 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -1989,6 +1989,8 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"حسب ضرورت ایپ کی اطلاع"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="APP">%1$s</xliff:g> کو <xliff:g id="ACCOUNT">%2$s</xliff:g> کے ساتھ ایک نیا صارف بنانے کی اجازت دیں (اس اکاؤنٹ کے ساتھ ایک صارف پہلے سے موجود ہے) ؟"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="ACCOUNT">%2$s</xliff:g> کے ساتھ نئے صارف کو تخلیق کرنے کے لیے <xliff:g id="APP">%1$s</xliff:g> کو اجازت دیں ؟"</string>
+    <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+    <skip />
     <string name="language_selection_title" msgid="52674936078683285">"ایک زبان شامل کریں"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"علاقہ کی ترجیح"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"زبان کا نام ٹائپ کریں"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index a40b67f..ab03056 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -1989,6 +1989,7 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Maxsus ilova bildirishnomasi"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="APP">%1$s</xliff:g> ilovasiga <xliff:g id="ACCOUNT">%2$s</xliff:g> hisobi bilan yangi foydalanuvchi yaratishiga ruxsat berilsinmi (bunday hisobdagi foydalanuvchi allaqachon mavjud) ?"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="APP">%1$s</xliff:g> ilovasiga <xliff:g id="ACCOUNT">%2$s</xliff:g> hisobi bilan yangi foydalanuvchi yaratishiga ruxsat berilsinmi ?"</string>
+    <string name="supervised_user_creation_label" msgid="6884904353827427515">"Kuzatuvdagi foydalanuvchi qoʻshish"</string>
     <string name="language_selection_title" msgid="52674936078683285">"Til qoʻshish"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"Hudud sozlamalari"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Til nomini kiriting"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 1731b3b..9225c16 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -1989,6 +1989,7 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Thông báo tùy chỉnh cho ứng dụng"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"Cho phép <xliff:g id="APP">%1$s</xliff:g> tạo người dùng mới bằng <xliff:g id="ACCOUNT">%2$s</xliff:g> (đã tồn tại người dùng có tài khoản này)?"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"Cho phép <xliff:g id="APP">%1$s</xliff:g> tạo người dùng mới bằng <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+    <string name="supervised_user_creation_label" msgid="6884904353827427515">"Thêm người dùng được giám sát"</string>
     <string name="language_selection_title" msgid="52674936078683285">"Thêm ngôn ngữ"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"Tùy chọn khu vực"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Nhập tên ngôn ngữ"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 8ce9ab2..6793baa 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -1989,6 +1989,8 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"自定义应用通知"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"允许<xliff:g id="APP">%1$s</xliff:g>使用 <xliff:g id="ACCOUNT">%2$s</xliff:g>(目前已有用户使用此帐号)创建新用户吗?"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"允许<xliff:g id="APP">%1$s</xliff:g>使用 <xliff:g id="ACCOUNT">%2$s</xliff:g> 创建新用户吗?"</string>
+    <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+    <skip />
     <string name="language_selection_title" msgid="52674936078683285">"添加语言"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"区域偏好设置"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"输入语言名称"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 49850e14..d63bf16 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -1989,6 +1989,7 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"自訂應用程式通知"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"要允許 <xliff:g id="APP">%1$s</xliff:g> 使用 <xliff:g id="ACCOUNT">%2$s</xliff:g> 建立新使用者 (此帳戶目前已有此使用者) 嗎?"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"要允許 <xliff:g id="APP">%1$s</xliff:g> 使用 <xliff:g id="ACCOUNT">%2$s</xliff:g> 建立新使用者嗎?"</string>
+    <string name="supervised_user_creation_label" msgid="6884904353827427515">"新增受管使用者"</string>
     <string name="language_selection_title" msgid="52674936078683285">"新增語言"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"地區偏好設定"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"輸入語言名稱"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 329b5dc..8890f66 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1989,6 +1989,8 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"自訂應用程式通知"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"要允許「<xliff:g id="APP">%1$s</xliff:g>」替 <xliff:g id="ACCOUNT">%2$s</xliff:g> (這個帳戶目前已有使用者) 建立新使用者嗎?"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"要允許「<xliff:g id="APP">%1$s</xliff:g>」替 <xliff:g id="ACCOUNT">%2$s</xliff:g> 建立新使用者嗎?"</string>
+    <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+    <skip />
     <string name="language_selection_title" msgid="52674936078683285">"新增語言"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"地區偏好設定"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"請輸入語言名稱"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 8c7d5ea..bfc0f1b 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -1989,6 +1989,8 @@
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Isaziso sohlelo lokusebenza olungokwezifiso"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"Vumela i-<xliff:g id="APP">%1$s</xliff:g> ukuthi idale umsebenzisi omusha nge-<xliff:g id="ACCOUNT">%2$s</xliff:g> (Umsebenzisi onale akhawunti usevele ukhona) ?"</string>
     <string name="user_creation_adding" msgid="7305185499667958364">"Vumela i-<xliff:g id="APP">%1$s</xliff:g> ukuthi idale umsebenzisi omusha nge-<xliff:g id="ACCOUNT">%2$s</xliff:g> ?"</string>
+    <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+    <skip />
     <string name="language_selection_title" msgid="52674936078683285">"Engeza ulimi"</string>
     <string name="country_selection_title" msgid="5221495687299014379">"Okuncamelayo kwesifunda"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Thayipha igama lolimi"</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 8aa9201..1705371 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -8440,6 +8440,8 @@
         <!-- Component name of an activity that allows the user to modify
              the settings for this dream. -->
         <attr name="settingsActivity" />
+        <!-- A preview, in a drawable resource id, of what the Dream will look like. -->
+        <attr name="previewImage" format="reference" />
     </declare-styleable>
 
     <!--  Use <code>trust-agent</code> as the root tag of the XML resource that
@@ -8778,6 +8780,14 @@
         <attr name="hotwordDetectionService" format="string" />
     </declare-styleable>
 
+    <!-- Use <code>game-service</code> as the root tag of the XML resource that
+         describes a GameService.
+         Described here are the attributes that can be included in that tag. -->
+    <declare-styleable name="GameService">
+        <!-- The service that hosts active game sessions.  This is required. -->
+        <attr name="gameSessionService" format="string" />
+    </declare-styleable>
+
     <!-- Use <code>voice-enrollment-application</code>
          as the root tag of the XML resource that escribes the supported keyphrases (hotwords)
          by the enrollment application.
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 06f347f..db24475 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -3070,7 +3070,6 @@
     <declare-styleable name="AndroidManifestMetaData"
          parent="AndroidManifestApplication
                  AndroidManifestActivity
-                 AndroidManifestApexSystemService
                  AndroidManifestReceiver
                  AndroidManifestProvider
                  AndroidManifestService
@@ -3105,7 +3104,6 @@
     <declare-styleable name="AndroidManifestProperty"
          parent="AndroidManifestApplication
                  AndroidManifestActivity
-                 AndroidManifestApexSystemService
                  AndroidManifestReceiver
                  AndroidManifestProvider
                  AndroidManifestService">
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index be32c42..7d8bcea 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2897,6 +2897,10 @@
     <!-- Make the IME killable by the lowmemorykiller by raising its oom_score_adj. -->
     <bool name="config_killableInputMethods">false</bool>
 
+    <!-- Prevent the InputMethodManagerService from starting up the IME unless
+     the currently focused view is a text editor. -->
+    <bool name="config_preventImeStartupUnlessTextEditor">false</bool>
+
     <!-- The list of classes that should be added to the notification ranking pipeline.
      See {@link com.android.server.notification.NotificationSignalExtractor}
       If you add a new extractor to this list make sure to update
@@ -5550,4 +5554,7 @@
          That button will fire an intent targeted for this package with the mentioned action.
          When this resource is empty, that button will not be shown. -->
     <string name="config_supervisedUserCreationPackage" translatable="false"></string>
+
+    <!-- Determines whether SafetyCenter feature is enabled. -->
+    <bool name="config_enableSafetyCenter">true</bool>
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 3d3c860..9449f60 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3250,6 +3250,8 @@
     <public name="supportedTypes" />
     <public name="resetEnabledSettingsOnAppDataCleared" />
     <public name="supportsStylusHandwriting" />
+    <!-- @hide @SystemApi -->
+    <public name="gameSessionService" />
   </staging-public-group>
 
   <staging-public-group type="id" first-id="0x01de0000">
@@ -3261,6 +3263,7 @@
   </staging-public-group>
 
   <staging-public-group type="style" first-id="0x01dd0000">
+    <public name="TextAppearance.DeviceDefault.Headline" />
   </staging-public-group>
 
   <staging-public-group type="string" first-id="0x01dc0000">
@@ -3279,6 +3282,8 @@
   </staging-public-group>
 
   <staging-public-group type="array" first-id="0x01d90000">
+    <!-- @hide @SystemApi -->
+    <public name="config_optionalIpSecAlgorithms" />
   </staging-public-group>
 
   <staging-public-group type="drawable" first-id="0x01d80000">
@@ -3311,6 +3316,8 @@
   <staging-public-group type="bool" first-id="0x01cf0000">
     <!-- @hide @SystemApi -->
     <public name="config_systemCaptionsServiceCallsEnabled" />
+    <!-- @hide @TestApi -->
+    <public name="config_preventImeStartupUnlessTextEditor" />
   </staging-public-group>
 
   <staging-public-group type="fraction" first-id="0x01ce0000">
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index b16e462..2879759 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1237,8 +1237,11 @@
     <string name="permlab_bodySensors">access body sensors (like heart rate monitors)
     </string>
     <!-- Description of the body sensors permission, listed so the user can decide whether to allow the application to access data from body sensors. [CHAR LIMIT=NONE] -->
-    <string name="permdesc_bodySensors" product="default">Allows the app to access data from sensors
-    that monitor your physical condition, such as your heart rate.</string>
+    <string name="permdesc_bodySensors" product="default">Access to data from body sensors such as heart rate, temperature, blood oxygen percentage, etc.</string>
+    <!-- Title of the background body sensors permission, listed so the user can decide whether to allow the application to access body sensor data in the background. [CHAR LIMIT=80] -->
+    <string name="permlab_bodySensors_background">access body sensors (like heart rate monitors) while in the background</string>
+    <!-- Description of the background body sensors permission, listed so the user can decide whether to allow the application to access data from body sensors in the background. [CHAR LIMIT=NONE] -->
+    <string name="permdesc_bodySensors_background" product="default">Access to data from body sensors such as heart rate, temperature, blood oxygen percentage, etc. while in the background.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_readCalendar">Read calendar events and details</string>
@@ -2009,6 +2012,11 @@
     <string name="permdesc_startViewPermissionUsage">Allows the holder to start the permission usage for an app. Should never be needed for normal apps.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=NONE] -->
+    <string name="permlab_startReviewPermissionDecisions">start view permission decisions</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=NONE] -->
+    <string name="permdesc_startReviewPermissionDecisions">Allows the holder to start screen to review permission decisions. Should never be needed for normal apps.</string>
+
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=NONE] -->
     <string name="permlab_startViewAppFeatures">start view app features</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=NONE] -->
     <string name="permdesc_startViewAppFeatures">Allows the holder to start viewing the features info for an app.</string>
diff --git a/core/res/res/values/styles_device_defaults.xml b/core/res/res/values/styles_device_defaults.xml
index ad0d0e0..dcfca84 100644
--- a/core/res/res/values/styles_device_defaults.xml
+++ b/core/res/res/values/styles_device_defaults.xml
@@ -42,6 +42,7 @@
         <item name="outlineSpotShadowColor">@color/btn_colored_background_material</item>
         <item name="textAppearance">?attr/textAppearanceButton</item>
         <item name="textColor">@color/btn_colored_text_material</item>
+        <item name="drawableTint">@color/btn_colored_text_material</item>
     </style>
     <style name="Widget.DeviceDefault.TextView" parent="Widget.Material.TextView" />
     <style name="Widget.DeviceDefault.CheckedTextView" parent="Widget.Material.CheckedTextView"/>
@@ -397,7 +398,7 @@
         <item name="fontFamily">@string/config_bodyFontFamily</item>
     </style>
     <style name="TextAppearance.DeviceDefault.Headline" parent="TextAppearance.Material.Headline">
-        <item name="fontFamily">@string/config_bodyFontFamily</item>
+        <item name="fontFamily">@string/config_headlineFontFamily</item>
     </style>
     <style name="TextAppearance.DeviceDefault.Display1" parent="TextAppearance.Material.Display1">
         <item name="fontFamily">@string/config_bodyFontFamily</item>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 527865f..ba4aa81 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2250,6 +2250,7 @@
   <java-symbol type="bool" name="config_autoResetAirplaneMode" />
   <java-symbol type="string" name="config_notificationAccessConfirmationActivity" />
   <java-symbol type="bool" name="config_killableInputMethods" />
+  <java-symbol type="bool" name="config_preventImeStartupUnlessTextEditor" />
 
   <java-symbol type="layout" name="resolver_list" />
   <java-symbol type="id" name="resolver_list" />
@@ -4634,4 +4635,6 @@
   <java-symbol type="string" name="config_systemGameService" />
 
   <java-symbol type="string" name="config_supervisedUserCreationPackage"/>
+
+  <java-symbol type="bool" name="config_enableSafetyCenter" />
 </resources>
diff --git a/core/tests/coretests/src/android/app/ApplicationPackageManagerTest.java b/core/tests/coretests/src/android/app/ApplicationPackageManagerTest.java
index 2c3c1ed..9bb064c 100644
--- a/core/tests/coretests/src/android/app/ApplicationPackageManagerTest.java
+++ b/core/tests/coretests/src/android/app/ApplicationPackageManagerTest.java
@@ -25,6 +25,7 @@
 import android.content.pm.PackageInfo;
 import android.os.storage.StorageManager;
 import android.os.storage.VolumeInfo;
+import android.platform.test.annotations.Presubmit;
 
 import androidx.annotation.NonNull;
 import androidx.test.filters.LargeTest;
@@ -39,6 +40,7 @@
 import java.util.Arrays;
 import java.util.List;
 
+@Presubmit
 @LargeTest
 public class ApplicationPackageManagerTest extends TestCase {
     private static final String sInternalVolPath = "/data";
diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
index 5db6a3e..bfb2fd5 100644
--- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
+++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
@@ -273,13 +273,14 @@
             newerConfig.orientation = orientation == ORIENTATION_LANDSCAPE
                     ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
             newerConfig.seq = seq + 2;
-            final ActivityClientRecord r = getActivityClientRecord(activity);
-            activityThread.updatePendingActivityConfiguration(r, newerConfig);
+            activityThread.updatePendingActivityConfiguration(activity.getActivityToken(),
+                    newerConfig);
 
             final Configuration olderConfig = new Configuration();
             olderConfig.orientation = orientation;
             olderConfig.seq = seq + 1;
 
+            final ActivityClientRecord r = getActivityClientRecord(activity);
             activityThread.handleActivityConfigurationChanged(r, olderConfig, INVALID_DISPLAY);
             assertEquals(numOfConfig, activity.mNumOfConfigChanges);
             assertEquals(olderConfig.orientation, activity.mConfig.orientation);
@@ -504,7 +505,8 @@
                     ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT;
 
             final ActivityClientRecord r = getActivityClientRecord(activity);
-            activityThread.updatePendingActivityConfiguration(r, newActivityConfig);
+            activityThread.updatePendingActivityConfiguration(activity.getActivityToken(),
+                    newActivityConfig);
             activityThread.handleActivityConfigurationChanged(r, newActivityConfig,
                     INVALID_DISPLAY);
 
diff --git a/core/tests/coretests/src/android/content/ContentProviderTest.java b/core/tests/coretests/src/android/content/ContentProviderTest.java
index ceebc62..c9a6d22 100644
--- a/core/tests/coretests/src/android/content/ContentProviderTest.java
+++ b/core/tests/coretests/src/android/content/ContentProviderTest.java
@@ -24,6 +24,7 @@
 import android.content.pm.ProviderInfo;
 import android.net.Uri;
 import android.os.UserHandle;
+import android.platform.test.annotations.Presubmit;
 
 import androidx.test.runner.AndroidJUnit4;
 
@@ -32,6 +33,7 @@
 import org.junit.runner.RunWith;
 import org.mockito.Answers;
 
+@Presubmit
 @RunWith(AndroidJUnit4.class)
 public class ContentProviderTest {
 
diff --git a/core/tests/coretests/src/android/content/ContentResolverTest.java b/core/tests/coretests/src/android/content/ContentResolverTest.java
index 01e240a..7b70b41 100644
--- a/core/tests/coretests/src/android/content/ContentResolverTest.java
+++ b/core/tests/coretests/src/android/content/ContentResolverTest.java
@@ -35,6 +35,7 @@
 import android.os.MemoryFile;
 import android.os.ParcelFileDescriptor;
 import android.os.SystemClock;
+import android.platform.test.annotations.Presubmit;
 import android.util.Size;
 
 import androidx.test.InstrumentationRegistry;
@@ -45,6 +46,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+@Presubmit
 @RunWith(AndroidJUnit4.class)
 public class ContentResolverTest {
 
diff --git a/core/tests/coretests/src/android/content/ContextTest.java b/core/tests/coretests/src/android/content/ContextTest.java
index 3d7d807..e4a9ce5 100644
--- a/core/tests/coretests/src/android/content/ContextTest.java
+++ b/core/tests/coretests/src/android/content/ContextTest.java
@@ -34,6 +34,7 @@
 import android.hardware.display.VirtualDisplay;
 import android.media.ImageReader;
 import android.os.UserHandle;
+import android.platform.test.annotations.Presubmit;
 import android.view.Display;
 
 import androidx.test.core.app.ApplicationProvider;
@@ -48,6 +49,7 @@
  *  Build/Install/Run:
  *   atest FrameworksCoreTests:ContextTest
  */
+@Presubmit
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class ContextTest {
diff --git a/core/tests/coretests/src/android/content/ManagedUserContentResolverTest.java b/core/tests/coretests/src/android/content/ManagedUserContentResolverTest.java
index 1bc46a7..68d4cd4 100644
--- a/core/tests/coretests/src/android/content/ManagedUserContentResolverTest.java
+++ b/core/tests/coretests/src/android/content/ManagedUserContentResolverTest.java
@@ -20,6 +20,7 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.platform.test.annotations.Presubmit;
 
 import androidx.test.filters.LargeTest;
 
@@ -36,6 +37,7 @@
  * Run: adb shell am instrument -e class android.content.ManagedUserContentResolverTest -w \
  *     com.android.frameworks.coretests/androidx.test.runner.AndroidJUnitRunner
  */
+@Presubmit
 @LargeTest
 public class ManagedUserContentResolverTest extends AbstractCrossUserContentResolverTest {
     @Override
diff --git a/core/tests/coretests/src/android/content/SecondaryUserContentResolverTest.java b/core/tests/coretests/src/android/content/SecondaryUserContentResolverTest.java
index dbe0278..de4c572 100644
--- a/core/tests/coretests/src/android/content/SecondaryUserContentResolverTest.java
+++ b/core/tests/coretests/src/android/content/SecondaryUserContentResolverTest.java
@@ -18,6 +18,7 @@
 
 import android.content.pm.UserInfo;
 import android.os.RemoteException;
+import android.platform.test.annotations.Presubmit;
 
 import androidx.test.filters.LargeTest;
 
@@ -34,6 +35,7 @@
  * Run: adb shell am instrument -e class android.content.SecondaryUserContentResolverTest -w \
  *     com.android.frameworks.coretests/androidx.test.runner.AndroidJUnitRunner
  */
+@Presubmit
 @LargeTest
 public class SecondaryUserContentResolverTest extends AbstractCrossUserContentResolverTest {
     @Override
diff --git a/core/tests/coretests/src/android/net/NetworkPolicyTest.kt b/core/tests/coretests/src/android/net/NetworkPolicyTest.kt
index d936cad..3c8f90c 100644
--- a/core/tests/coretests/src/android/net/NetworkPolicyTest.kt
+++ b/core/tests/coretests/src/android/net/NetworkPolicyTest.kt
@@ -16,6 +16,10 @@
 
 package android.net
 
+import android.net.NetworkTemplate.MATCH_BLUETOOTH
+import android.net.NetworkTemplate.MATCH_ETHERNET
+import android.net.NetworkTemplate.MATCH_MOBILE
+import android.net.NetworkTemplate.MATCH_WIFI
 import android.text.format.Time.TIMEZONE_UTC
 import androidx.test.runner.AndroidJUnit4
 import org.junit.Test
@@ -24,16 +28,18 @@
 import java.io.DataInputStream
 import java.time.ZoneId
 import kotlin.test.assertEquals
+import kotlin.test.assertFalse
+import kotlin.test.assertTrue
 
 private const val TEST_IMSI1 = "TESTIMSI1"
-private const val TEST_SSID1 = "TESTISSID1"
+private const val TEST_WIFI_NETWORK_KEY1 = "TESTKEY1"
 
 @RunWith(AndroidJUnit4::class)
 class NetworkPolicyTest {
     @Test
     fun testTemplateBackupRestore() {
         assertPolicyBackupRestore(createTestPolicyForTemplate(
-                NetworkTemplate.buildTemplateWifi(TEST_SSID1)))
+                NetworkTemplate.buildTemplateWifi(TEST_WIFI_NETWORK_KEY1)))
         assertPolicyBackupRestore(createTestPolicyForTemplate(
                 NetworkTemplate.buildTemplateMobileAll(TEST_IMSI1)))
         assertPolicyBackupRestore(createTestPolicyForTemplate(
@@ -53,4 +59,26 @@
         val restored = NetworkPolicy.getNetworkPolicyFromBackup(stream)
         assertEquals(policy, restored)
     }
-}
\ No newline at end of file
+
+    @Test
+    fun testIsTemplatePersistable() {
+        listOf(MATCH_MOBILE, MATCH_WIFI).forEach {
+            // Verify wildcard templates cannot be persistable.
+            assertFalse(NetworkPolicy.isTemplatePersistable(NetworkTemplate.Builder(it).build()))
+
+            // Verify mobile/wifi templates can be persistable if the Subscriber Id is supplied.
+            assertTrue(NetworkPolicy.isTemplatePersistable(NetworkTemplate.Builder(it)
+                    .setSubscriberIds(setOf(TEST_IMSI1)).build()))
+        }
+
+        // Verify bluetooth and ethernet templates can be persistable without any other
+        // field is supplied.
+        listOf(MATCH_BLUETOOTH, MATCH_ETHERNET).forEach {
+            assertTrue(NetworkPolicy.isTemplatePersistable(NetworkTemplate.Builder(it).build()))
+        }
+
+        // Verify wifi template can be persistable if the Wifi Network Key is supplied.
+        assertTrue(NetworkPolicy.isTemplatePersistable(NetworkTemplate.Builder(MATCH_WIFI)
+                .setWifiNetworkKeys(setOf(TEST_WIFI_NETWORK_KEY1)).build()))
+    }
+}
diff --git a/core/tests/coretests/src/android/os/BundleTest.java b/core/tests/coretests/src/android/os/BundleTest.java
index 09f4840..a3bda8b 100644
--- a/core/tests/coretests/src/android/os/BundleTest.java
+++ b/core/tests/coretests/src/android/os/BundleTest.java
@@ -23,6 +23,7 @@
 import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.assertTrue;
 
+import android.platform.test.annotations.Presubmit;
 import android.util.Log;
 
 import androidx.test.filters.SmallTest;
@@ -41,6 +42,7 @@
  * Run with: atest FrameworksCoreTests:android.os.BundleTest
  */
 @SmallTest
+@Presubmit
 @RunWith(AndroidJUnit4.class)
 public class BundleTest {
     private Log.TerribleFailureHandler mWtfHandler;
diff --git a/core/tests/coretests/src/android/os/storage/StorageManagerBaseTest.java b/core/tests/coretests/src/android/os/storage/StorageManagerBaseTest.java
index 7ccbb01..e6660f3 100644
--- a/core/tests/coretests/src/android/os/storage/StorageManagerBaseTest.java
+++ b/core/tests/coretests/src/android/os/storage/StorageManagerBaseTest.java
@@ -170,7 +170,7 @@
         when(mFile.getUsableSpace()).thenReturn(10000L);
         when(mFile.getTotalSpace()).thenReturn(100000L);
         long result = mSm.getStorageCacheBytes(mFile, 0);
-        assertThat(result).isEqualTo(4666L);
+        assertThat(result).isEqualTo(4667L);
     }
 
     /**
diff --git a/core/tests/coretests/src/android/view/HandwritingInitiatorTest.java b/core/tests/coretests/src/android/view/HandwritingInitiatorTest.java
new file mode 100644
index 0000000..8f04461
--- /dev/null
+++ b/core/tests/coretests/src/android/view/HandwritingInitiatorTest.java
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.MotionEvent.ACTION_DOWN;
+import static android.view.MotionEvent.ACTION_MOVE;
+import static android.view.MotionEvent.ACTION_UP;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.Instrumentation;
+import android.content.Context;
+import android.graphics.Rect;
+import android.platform.test.annotations.Presubmit;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodManager;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for {@link HandwritingInitiator}
+ *
+ * Build/Install/Run:
+ *  atest FrameworksCoreTests:HandwritingInitiatorTest
+ */
+@Presubmit
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class HandwritingInitiatorTest {
+    private static final int TOUCH_SLOP = 8;
+    private static final long TAP_TIMEOUT = ViewConfiguration.getTapTimeout();
+    private static final Rect sHwArea = new Rect(100, 200, 500, 500);
+    private static final EditorInfo sFakeEditorInfo = new EditorInfo();
+
+    private HandwritingInitiator mHandwritingInitiator;
+    private View mTestView;
+
+    @Before
+    public void setup() {
+        final Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        Context context = mInstrumentation.getTargetContext();
+        ViewConfiguration viewConfiguration = mock(ViewConfiguration.class);
+        when(viewConfiguration.getScaledTouchSlop()).thenReturn(TOUCH_SLOP);
+
+        InputMethodManager inputMethodManager = context.getSystemService(InputMethodManager.class);
+        mHandwritingInitiator =
+                spy(new HandwritingInitiator(viewConfiguration, inputMethodManager));
+        mHandwritingInitiator.updateEditorBound(sHwArea);
+
+        // mock a parent so that HandwritingInitiator can get
+        ViewGroup parent = new ViewGroup(context) {
+            @Override
+            protected void onLayout(boolean changed, int l, int t, int r, int b) {
+                // We don't layout this view.
+            }
+            @Override
+            public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) {
+                r.left = sHwArea.left;
+                r.top = sHwArea.top;
+                r.right = sHwArea.right;
+                r.bottom = sHwArea.bottom;
+                return true;
+            }
+        };
+
+        mTestView = mock(View.class);
+        when(mTestView.isAttachedToWindow()).thenReturn(true);
+        parent.addView(mTestView);
+    }
+
+    @Test
+    public void onTouchEvent_startHandwriting_when_stylusMoveOnce_withinHWArea() {
+        mHandwritingInitiator.onInputConnectionCreated(mTestView, sFakeEditorInfo);
+        final int x1 = (sHwArea.left + sHwArea.right) / 2;
+        final int y1 = (sHwArea.top + sHwArea.bottom) / 2;
+        MotionEvent stylusEvent1 = createStylusEvent(ACTION_DOWN, x1, y1, 0);
+        mHandwritingInitiator.onTouchEvent(stylusEvent1);
+
+        final int x2 = x1 + TOUCH_SLOP * 2;
+        final int y2 = y1;
+
+        MotionEvent stylusEvent2 = createStylusEvent(ACTION_MOVE, x2, y2, 0);
+        mHandwritingInitiator.onTouchEvent(stylusEvent2);
+
+        // Stylus movement win HandwritingArea should trigger IMM.startHandwriting once.
+        verify(mHandwritingInitiator, times(1)).startHandwriting(mTestView);
+    }
+
+    @Test
+    public void onTouchEvent_startHandwritingOnce_when_stylusMoveMultiTimes_withinHWArea() {
+        mHandwritingInitiator.onInputConnectionCreated(mTestView, sFakeEditorInfo);
+        final int x1 = (sHwArea.left + sHwArea.right) / 2;
+        final int y1 = (sHwArea.top + sHwArea.bottom) / 2;
+        MotionEvent stylusEvent1 = createStylusEvent(ACTION_DOWN, x1, y1, 0);
+        mHandwritingInitiator.onTouchEvent(stylusEvent1);
+
+        final int x2 = x1 + TOUCH_SLOP * 2;
+        final int y2 = y1;
+        MotionEvent stylusEvent2 = createStylusEvent(ACTION_MOVE, x2, y2, 0);
+        mHandwritingInitiator.onTouchEvent(stylusEvent2);
+
+
+        final int x3 = x2 + TOUCH_SLOP * 2;
+        final int y3 = y2;
+        MotionEvent stylusEvent3 = createStylusEvent(ACTION_MOVE, x3, y3, 0);
+        mHandwritingInitiator.onTouchEvent(stylusEvent3);
+
+        MotionEvent stylusEvent4 = createStylusEvent(ACTION_UP, x2, y2, 0);
+        mHandwritingInitiator.onTouchEvent(stylusEvent4);
+
+        // It only calls startHandwriting once for each ACTION_DOWN.
+        verify(mHandwritingInitiator, times(1)).startHandwriting(mTestView);
+    }
+
+    @Test
+    public void onTouchEvent_startHandwriting_inputConnectionBuiltAfterStylusMove() {
+        final int x1 = (sHwArea.left + sHwArea.right) / 2;
+        final int y1 = (sHwArea.top + sHwArea.bottom) / 2;
+        MotionEvent stylusEvent1 = createStylusEvent(ACTION_DOWN, x1, y1, 0);
+        mHandwritingInitiator.onTouchEvent(stylusEvent1);
+
+        final int x2 = x1 + TOUCH_SLOP * 2;
+        final int y2 = y1;
+        MotionEvent stylusEvent2 = createStylusEvent(ACTION_MOVE, x2, y2, 0);
+        mHandwritingInitiator.onTouchEvent(stylusEvent2);
+
+        // InputConnection is created after stylus movement.
+        mHandwritingInitiator.onInputConnectionCreated(mTestView, sFakeEditorInfo);
+
+        verify(mHandwritingInitiator, times(1)).startHandwriting(mTestView);
+    }
+
+    @Test
+    public void onTouchEvent_notStartHandwriting_when_stylusTap_withinHWArea() {
+        mHandwritingInitiator.onInputConnectionCreated(mTestView, sFakeEditorInfo);
+        final int x1 = 200;
+        final int y1 = 200;
+        MotionEvent stylusEvent1 = createStylusEvent(ACTION_DOWN, x1, y1, 0);
+        mHandwritingInitiator.onTouchEvent(stylusEvent1);
+
+        final int x2 = x1 + TOUCH_SLOP / 2;
+        final int y2 = y1;
+        MotionEvent stylusEvent2 = createStylusEvent(ACTION_UP, x2, y2, 0);
+        mHandwritingInitiator.onTouchEvent(stylusEvent2);
+
+        verify(mHandwritingInitiator, never()).startHandwriting(mTestView);
+    }
+
+    @Test
+    public void onTouchEvent_notStartHandwriting_when_stylusMove_outOfHWArea() {
+        mHandwritingInitiator.onInputConnectionCreated(mTestView, sFakeEditorInfo);
+        final int x1 = 10;
+        final int y1 = 10;
+        MotionEvent stylusEvent1 = createStylusEvent(ACTION_DOWN, x1, y1, 0);
+        mHandwritingInitiator.onTouchEvent(stylusEvent1);
+
+        final int x2 = x1 + TOUCH_SLOP * 2;
+        final int y2 = y1;
+        MotionEvent stylusEvent2 = createStylusEvent(ACTION_MOVE, x2, y2, 0);
+        mHandwritingInitiator.onTouchEvent(stylusEvent2);
+
+        verify(mHandwritingInitiator, never()).startHandwriting(mTestView);
+    }
+
+    @Test
+    public void onTouchEvent_notStartHandwriting_when_stylusMove_afterTapTimeOut() {
+        mHandwritingInitiator.onInputConnectionCreated(mTestView, sFakeEditorInfo);
+        final int x1 = 10;
+        final int y1 = 10;
+        final long time1 = 10L;
+        MotionEvent stylusEvent1 = createStylusEvent(ACTION_DOWN, x1, y1, 0);
+        mHandwritingInitiator.onTouchEvent(stylusEvent1);
+
+        final int x2 = x1 + TOUCH_SLOP * 2;
+        final int y2 = y1;
+        final long time2 = time1 + TAP_TIMEOUT + 10L;
+        MotionEvent stylusEvent2 = createStylusEvent(ACTION_MOVE, x2, y2, time2);
+        mHandwritingInitiator.onTouchEvent(stylusEvent2);
+
+        // stylus movement is after TAP_TIMEOUT it shouldn't call startHandwriting.
+        verify(mHandwritingInitiator, never()).startHandwriting(mTestView);
+    }
+
+    @Test
+    public void onInputConnectionCreated_inputConnectionCreated() {
+        mHandwritingInitiator.onInputConnectionCreated(mTestView, sFakeEditorInfo);
+        assertThat(mHandwritingInitiator.mConnectedView).isNotNull();
+        assertThat(mHandwritingInitiator.mConnectedView.get()).isEqualTo(mTestView);
+    }
+
+    @Test
+    public void onInputConnectionCreated_inputConnectionClosed() {
+        mHandwritingInitiator.onInputConnectionCreated(mTestView, sFakeEditorInfo);
+        mHandwritingInitiator.onInputConnectionClosed(mTestView);
+
+        assertThat(mHandwritingInitiator.mConnectedView).isNull();
+        assertThat(mHandwritingInitiator.mEditorBound).isNull();
+    }
+
+    @Test
+    public void onInputConnectionCreated_inputConnectionRestarted() {
+        // When IMM restarts input connection, View#onInputConnectionCreatedInternal might be
+        // called before View#onInputConnectionClosedInternal. As a result, we need to handle the
+        // case where "one view "2 InputConnections".
+        mHandwritingInitiator.onInputConnectionCreated(mTestView, sFakeEditorInfo);
+        mHandwritingInitiator.onInputConnectionCreated(mTestView, sFakeEditorInfo);
+        mHandwritingInitiator.onInputConnectionClosed(mTestView);
+
+        assertThat(mHandwritingInitiator.mConnectedView).isNotNull();
+        assertThat(mHandwritingInitiator.mConnectedView.get()).isEqualTo(mTestView);
+    }
+
+    @Test
+    public void updateEditorBound() {
+        Rect rect = new Rect(1, 2, 3, 4);
+        mHandwritingInitiator.updateEditorBound(rect);
+
+        assertThat(mHandwritingInitiator.mEditorBound).isEqualTo(rect);
+    }
+
+    private MotionEvent createStylusEvent(int action, int x, int y, long eventTime) {
+        MotionEvent.PointerProperties[] properties = MotionEvent.PointerProperties.createArray(1);
+        properties[0].toolType = MotionEvent.TOOL_TYPE_STYLUS;
+
+        MotionEvent.PointerCoords[] coords = MotionEvent.PointerCoords.createArray(1);
+        coords[0].x = x;
+        coords[0].y = y;
+
+        return MotionEvent.obtain(0 /* downTime */, eventTime /* eventTime */, action, 1,
+                properties, coords, 0 /* metaState */, 0 /* buttonState */, 1 /* xPrecision */,
+                1 /* yPrecision */, 0 /* deviceId */, 0 /* edgeFlags */,
+                InputDevice.SOURCE_TOUCHSCREEN, 0 /* flags */);
+    }
+}
diff --git a/core/tests/coretests/src/android/view/MotionEventTest.java b/core/tests/coretests/src/android/view/MotionEventTest.java
index c4c983d..78a8f7b 100644
--- a/core/tests/coretests/src/android/view/MotionEventTest.java
+++ b/core/tests/coretests/src/android/view/MotionEventTest.java
@@ -16,7 +16,6 @@
 
 package android.view;
 
-import static android.view.InputDevice.SOURCE_CLASS_POINTER;
 import static android.view.MotionEvent.ACTION_DOWN;
 import static android.view.MotionEvent.ACTION_POINTER_DOWN;
 import static android.view.MotionEvent.TOOL_TYPE_FINGER;
@@ -215,27 +214,4 @@
         rotInvalid.transform(mat);
         assertEquals(-1, rotInvalid.getSurfaceRotation());
     }
-
-    @Test
-    public void testUsesPointerSourceByDefault() {
-        final MotionEvent event = MotionEvent.obtain(0 /* downTime */, 0 /* eventTime */,
-                ACTION_DOWN, 0 /* x */, 0 /* y */, 0 /* metaState */);
-        assertTrue(event.isFromSource(SOURCE_CLASS_POINTER));
-    }
-
-    @Test
-    public void testLocationOffsetOnlyAppliedToNonPointerSources() {
-        final MotionEvent event = MotionEvent.obtain(0 /* downTime */, 0 /* eventTime */,
-                ACTION_DOWN, 10 /* x */, 20 /* y */, 0 /* metaState */);
-        event.offsetLocation(40, 50);
-
-        // The offset should be applied since a pointer source is used by default.
-        assertEquals(50, (int) event.getX());
-        assertEquals(70, (int) event.getY());
-
-        // The offset should not be applied if the source is changed to a non-pointer source.
-        event.setSource(InputDevice.SOURCE_JOYSTICK);
-        assertEquals(10, (int) event.getX());
-        assertEquals(20, (int) event.getY());
-    }
 }
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityCacheTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityCacheTest.java
index e689b5d3..dd8cc6e 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityCacheTest.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityCacheTest.java
@@ -26,6 +26,8 @@
 import static junit.framework.Assert.assertNotNull;
 import static junit.framework.Assert.assertNull;
 
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static org.mockito.Matchers.anyBoolean;
 import static org.mockito.Matchers.anyObject;
@@ -997,6 +999,60 @@
         }
     }
 
+    @Test
+    public void enable_cacheEnabled() {
+        mAccessibilityCache.setEnabled(false);
+        assertFalse(mAccessibilityCache.isEnabled());
+
+        mAccessibilityCache.setEnabled(true);
+        assertTrue(mAccessibilityCache.isEnabled());
+    }
+
+    @Test
+    public void disable_cacheDisabled() {
+        mAccessibilityCache.setEnabled(false);
+        assertFalse(mAccessibilityCache.isEnabled());
+    }
+
+    @Test
+    public void queryNode_nodeIsInCache() {
+        AccessibilityNodeInfo info = new AccessibilityNodeInfo();
+        mAccessibilityCache.add(info);
+
+        assertTrue(mAccessibilityCache.isNodeInCache(info));
+    }
+
+    @Test
+    public void clearSubtreeWithNode_nodeInCacheInvalidated() {
+        AccessibilityNodeInfo info = new AccessibilityNodeInfo();
+        info.setSource(getMockViewWithA11yAndWindowIds(1, 1));
+        mAccessibilityCache.add(info);
+
+        mAccessibilityCache.clearSubTree(info);
+        assertFalse(mAccessibilityCache.isNodeInCache(info));
+    }
+
+    @Test
+    public void clearSubtreeWithNode_subtreeInCacheInvalidated() {
+        AccessibilityNodeInfo info = new AccessibilityNodeInfo();
+        View parentView = getMockViewWithA11yAndWindowIds(1, 1);
+        info.setSource(parentView);
+
+        AccessibilityNodeInfo childInfo = new AccessibilityNodeInfo();
+        View childView = getMockViewWithA11yAndWindowIds(2, 1);
+        childInfo.setSource(childView);
+
+        childInfo.setParent(parentView);
+        info.addChild(childView);
+        mAccessibilityCache.add(info);
+        mAccessibilityCache.add(childInfo);
+
+        mAccessibilityCache.clearSubTree(info);
+
+        assertFalse(mAccessibilityCache.isNodeInCache(info));
+        assertFalse(mAccessibilityCache.isNodeInCache(childInfo));
+    }
+
     private AccessibilityWindowInfo obtainAccessibilityWindowInfo(int windowId, int layer) {
         AccessibilityWindowInfo windowInfo = AccessibilityWindowInfo.obtain();
         windowInfo.setId(windowId);
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityEventTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityEventTest.java
index 2c8c385..6df9002 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityEventTest.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityEventTest.java
@@ -42,14 +42,14 @@
     // and assertAccessibilityEventCleared
 
     /** The number of properties of the {@link AccessibilityEvent} class. */
-    private static final int A11Y_EVENT_NON_STATIC_FIELD_COUNT = 34;
+    private static final int A11Y_EVENT_NON_STATIC_FIELD_COUNT = 32;
 
     // The number of fields tested in the corresponding CTS AccessibilityRecordTest:
     // assertAccessibilityRecordCleared, fullyPopulateAccessibilityRecord,
     // and assertEqualAccessibilityRecord
 
     /** The number of properties of the {@link AccessibilityRecord} class. */
-    private static final int A11Y_RECORD_NON_STATIC_FIELD_COUNT = 25;
+    private static final int A11Y_RECORD_NON_STATIC_FIELD_COUNT = 23;
 
     @Test
     public void testImportantForAccessibiity_getSetWorkAcrossParceling() {
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityManagerTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityManagerTest.java
index 212fdca..bb1a3b18 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityManagerTest.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityManagerTest.java
@@ -17,7 +17,6 @@
 package android.view.accessibility;
 
 import static junit.framework.TestCase.assertFalse;
-import static junit.framework.TestCase.assertSame;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
@@ -188,17 +187,6 @@
     }
 
     @Test
-    public void testSendAccessibilityEvent_AccessibilityEnabled() throws Exception {
-        AccessibilityEvent sentEvent = AccessibilityEvent.obtain(
-                AccessibilityEvent.TYPE_ANNOUNCEMENT);
-
-        AccessibilityManager manager = createManager(WITH_A11Y_ENABLED);
-        manager.sendAccessibilityEvent(sentEvent);
-
-        assertSame("The event should be recycled.", sentEvent, AccessibilityEvent.obtain());
-    }
-
-    @Test
     public void testSendAccessibilityEvent_AccessibilityDisabled() throws Exception {
         AccessibilityEvent sentEvent = AccessibilityEvent.obtain();
 
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java
index ad1f298..62d0b2e 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java
@@ -173,6 +173,8 @@
 
     public void setFocusAppearance(int strokeWidth, int color) {}
 
+    public void setCacheEnabled(boolean enabled) {}
+
     public void logTrace(long timestamp, String where, String callingParams, int processId,
             long threadId, int callingUid, Bundle callingStack) {}
 
diff --git a/core/tests/coretests/src/android/view/accessibility/RecycleAccessibilityEventTest.java b/core/tests/coretests/src/android/view/accessibility/RecycleAccessibilityEventTest.java
deleted file mode 100644
index 11f4e3c..0000000
--- a/core/tests/coretests/src/android/view/accessibility/RecycleAccessibilityEventTest.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/**
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
- * express or implied. See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.view.accessibility;
-
-import androidx.test.filters.SmallTest;
-
-import junit.framework.TestCase;
-
-/**
- * This class exercises the caching and recycling of {@link AccessibilityEvent}s.
- */
-public class RecycleAccessibilityEventTest extends TestCase {
-
-    private static final String CLASS_NAME = "foo.bar.baz.Test";
-    private static final String PACKAGE_NAME = "foo.bar.baz";
-    private static final String TEXT = "Some stuff";
-
-    private static final String CONTENT_DESCRIPTION = "Content description";
-    private static final int ITEM_COUNT = 10;
-    private static final int CURRENT_ITEM_INDEX = 1;
-
-    private static final int FROM_INDEX = 1;
-    private static final int ADDED_COUNT = 2;
-    private static final int REMOVED_COUNT = 1;
-
-    /**
-     * If an {@link AccessibilityEvent} is marshaled/unmarshaled correctly
-     */
-    @SmallTest
-    public void testAccessibilityEventViewTextChangedType() {
-        AccessibilityEvent first =
-            AccessibilityEvent.obtain(AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED);
-        assertNotNull(first);
-
-        first.setClassName(CLASS_NAME);
-        first.setPackageName(PACKAGE_NAME);
-        first.getText().add(TEXT);
-        first.setFromIndex(FROM_INDEX);
-        first.setAddedCount(ADDED_COUNT);
-        first.setRemovedCount(REMOVED_COUNT);
-        first.setChecked(true);
-        first.setContentDescription(CONTENT_DESCRIPTION);
-        first.setItemCount(ITEM_COUNT);
-        first.setCurrentItemIndex(CURRENT_ITEM_INDEX);
-        first.setEnabled(true);
-        first.setPassword(true);
-
-        first.recycle();
-
-        assertNotNull(first);
-        assertNull(first.getClassName());
-        assertNull(first.getPackageName());
-        assertEquals(0, first.getText().size());
-        assertFalse(first.isChecked());
-        assertNull(first.getContentDescription());
-        assertEquals(-1, first.getItemCount());
-        assertEquals(AccessibilityEvent.INVALID_POSITION, first.getCurrentItemIndex());
-        assertFalse(first.isEnabled());
-        assertFalse(first.isPassword());
-        assertEquals(-1, first.getFromIndex());
-        assertEquals(-1, first.getAddedCount());
-        assertEquals(-1, first.getRemovedCount());
-
-        // get another event from the pool (this must be the recycled first)
-        AccessibilityEvent second = AccessibilityEvent.obtain();
-        assertEquals(first, second);
-    }
-}
diff --git a/core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java b/core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java
index 9696fdf..4f95cb8 100644
--- a/core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java
+++ b/core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java
@@ -28,7 +28,7 @@
 import static androidx.test.espresso.matcher.ViewMatchers.withTagValue;
 import static androidx.test.espresso.matcher.ViewMatchers.withText;
 
-import static com.android.internal.widget.FloatingToolbarPopup.MenuItemRepr;
+import static com.android.internal.widget.floatingtoolbar.LocalFloatingToolbarPopup.MenuItemRepr;
 
 import static org.hamcrest.Matchers.allOf;
 import static org.hamcrest.Matchers.is;
@@ -42,7 +42,7 @@
 import androidx.test.espresso.ViewAction;
 import androidx.test.espresso.ViewInteraction;
 
-import com.android.internal.widget.FloatingToolbar;
+import com.android.internal.widget.floatingtoolbar.FloatingToolbar;
 
 import org.hamcrest.Description;
 import org.hamcrest.Matcher;
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserActivityLoggerFake.java b/core/tests/coretests/src/com/android/internal/app/ChooserActivityLoggerFake.java
index 374edb8..2ecc261 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityLoggerFake.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityLoggerFake.java
@@ -95,6 +95,13 @@
         return mCalls.get(index).event;
     }
 
+    public void removeCallsForUiEventsOfType(int uiEventType) {
+        mCalls.removeIf(
+                call ->
+                        (call.atomId == FrameworkStatsLog.UI_EVENT_REPORTED)
+                                && (call.event.getId() == uiEventType));
+    }
+
     @Override
     public void logShareStarted(int eventId, String packageName, String mimeType,
             int appProvidedDirect, int appProvidedApp, boolean isWorkprofile, int previewType,
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 c69cb4b..69ff7c6 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
@@ -45,6 +45,7 @@
 import static org.hamcrest.CoreMatchers.not;
 import static org.hamcrest.CoreMatchers.notNullValue;
 import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.greaterThan;
 import static org.junit.Assert.assertEquals;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
@@ -80,12 +81,12 @@
 import android.os.UserHandle;
 import android.provider.DeviceConfig;
 import android.service.chooser.ChooserTarget;
+import android.view.View;
 
 import androidx.annotation.CallSuper;
 import androidx.test.platform.app.InstrumentationRegistry;
 import androidx.test.rule.ActivityTestRule;
 
-import com.android.internal.R;
 import com.android.internal.app.ResolverActivity.ResolvedComponentInfo;
 import com.android.internal.app.chooser.DisplayResolveInfo;
 import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
@@ -93,6 +94,7 @@
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.util.FrameworkStatsLog;
 
+import org.hamcrest.Matcher;
 import org.junit.Before;
 import org.junit.Ignore;
 import org.junit.Rule;
@@ -178,6 +180,16 @@
         return clientIntent;
     }
 
+    /**
+     * Whether {@code #testIsAppPredictionServiceAvailable} should verify the behavior after
+     * changing the availability conditions at runtime. In the unbundled chooser, the availability
+     * is cached at start and will never be re-evaluated.
+     * TODO: remove when we no longer want to test the system's on-the-fly evaluation.
+     */
+    protected boolean shouldTestTogglingAppPredictionServiceAvailabilityAtRuntime() {
+        return true;
+    }
+
     /* --------
      * The code in this section is unorthodox and can be simplified/reverted when we no longer need
      * to support the parallel chooser implementations.
@@ -256,7 +268,7 @@
         waitForIdle();
         assertThat(activity.getAdapter().getCount(), is(2));
         assertThat(activity.getAdapter().getServiceTargetCount(), is(0));
-        onView(withId(R.id.title)).check(matches(withText("chooser test")));
+        onView(withIdFromRuntimeResource("title")).check(matches(withText("chooser test")));
     }
 
     @Test
@@ -275,7 +287,8 @@
                 .thenReturn(resolvedComponentInfos);
         mActivityRule.launchActivity(Intent.createChooser(sendIntent, "chooser test"));
         waitForIdle();
-        onView(withId(R.id.title)).check(matches(withText(R.string.whichSendApplication)));
+        onView(withIdFromRuntimeResource("title"))
+                .check(matches(withTextFromRuntimeResource("whichSendApplication")));
     }
 
     @Test
@@ -294,8 +307,8 @@
                 .thenReturn(resolvedComponentInfos);
         mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
         waitForIdle();
-        onView(withId(R.id.title))
-                .check(matches(withText(R.string.whichSendApplication)));
+        onView(withIdFromRuntimeResource("title"))
+                .check(matches(withTextFromRuntimeResource("whichSendApplication")));
     }
 
     @Test
@@ -314,8 +327,10 @@
                 .thenReturn(resolvedComponentInfos);
         mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
         waitForIdle();
-        onView(withId(R.id.content_preview_title)).check(matches(not(isDisplayed())));
-        onView(withId(R.id.content_preview_thumbnail)).check(matches(not(isDisplayed())));
+        onView(withIdFromRuntimeResource("content_preview_title"))
+                .check(matches(not(isDisplayed())));
+        onView(withIdFromRuntimeResource("content_preview_thumbnail"))
+                .check(matches(not(isDisplayed())));
     }
 
     @Test
@@ -335,9 +350,12 @@
                 .thenReturn(resolvedComponentInfos);
         mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
         waitForIdle();
-        onView(withId(R.id.content_preview_title)).check(matches(isDisplayed()));
-        onView(withId(R.id.content_preview_title)).check(matches(withText(previewTitle)));
-        onView(withId(R.id.content_preview_thumbnail)).check(matches(not(isDisplayed())));
+        onView(withIdFromRuntimeResource("content_preview_title"))
+                .check(matches(isDisplayed()));
+        onView(withIdFromRuntimeResource("content_preview_title"))
+                .check(matches(withText(previewTitle)));
+        onView(withIdFromRuntimeResource("content_preview_thumbnail"))
+                .check(matches(not(isDisplayed())));
     }
 
     @Test
@@ -358,8 +376,9 @@
                 .thenReturn(resolvedComponentInfos);
         mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
         waitForIdle();
-        onView(withId(R.id.content_preview_title)).check(matches(isDisplayed()));
-        onView(withId(R.id.content_preview_thumbnail)).check(matches(not(isDisplayed())));
+        onView(withIdFromRuntimeResource("content_preview_title")).check(matches(isDisplayed()));
+        onView(withIdFromRuntimeResource("content_preview_thumbnail"))
+                .check(matches(not(isDisplayed())));
     }
 
     @Test
@@ -382,8 +401,9 @@
                 .thenReturn(resolvedComponentInfos);
         mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
         waitForIdle();
-        onView(withId(R.id.content_preview_title)).check(matches(isDisplayed()));
-        onView(withId(R.id.content_preview_thumbnail)).check(matches(isDisplayed()));
+        onView(withIdFromRuntimeResource("content_preview_title")).check(matches(isDisplayed()));
+        onView(withIdFromRuntimeResource("content_preview_thumbnail"))
+                .check(matches(isDisplayed()));
     }
 
     @Test @Ignore
@@ -406,7 +426,7 @@
         waitForIdle();
 
         assertThat(activity.getAdapter().getCount(), is(2));
-        onView(withId(R.id.profile_button)).check(doesNotExist());
+        onView(withIdFromRuntimeResource("profile_button")).check(doesNotExist());
 
         ResolveInfo[] chosen = new ResolveInfo[1];
         ChooserActivityOverrideData.getInstance().onSafelyStartCallback = targetInfo -> {
@@ -536,8 +556,8 @@
         waitForIdle();
         assertThat(activity.isFinishing(), is(false));
 
-        onView(withId(R.id.empty)).check(matches(isDisplayed()));
-        onView(withId(R.id.profile_pager)).check(matches(not(isDisplayed())));
+        onView(withIdFromRuntimeResource("empty")).check(matches(isDisplayed()));
+        onView(withIdFromRuntimeResource("profile_pager")).check(matches(not(isDisplayed())));
         InstrumentationRegistry.getInstrumentation().runOnMainSync(
                 () -> wrapper.getAdapter().handlePackagesChanged()
         );
@@ -700,8 +720,8 @@
                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
         waitForIdle();
 
-        onView(withId(R.id.chooser_copy_button)).check(matches(isDisplayed()));
-        onView(withId(R.id.chooser_copy_button)).perform(click());
+        onView(withIdFromRuntimeResource("chooser_copy_button")).check(matches(isDisplayed()));
+        onView(withIdFromRuntimeResource("chooser_copy_button")).perform(click());
         ClipboardManager clipboard = (ClipboardManager) activity.getSystemService(
                 Context.CLIPBOARD_SERVICE);
         ClipData clipData = clipboard.getPrimaryClip();
@@ -729,8 +749,8 @@
         mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
         waitForIdle();
 
-        onView(withId(R.id.chooser_copy_button)).check(matches(isDisplayed()));
-        onView(withId(R.id.chooser_copy_button)).perform(click());
+        onView(withIdFromRuntimeResource("chooser_copy_button")).check(matches(isDisplayed()));
+        onView(withIdFromRuntimeResource("chooser_copy_button")).perform(click());
 
         verify(mockLogger, atLeastOnce()).write(logMakerCaptor.capture());
 
@@ -755,12 +775,17 @@
                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
         waitForIdle();
 
-        onView(withId(R.id.chooser_nearby_button)).check(matches(isDisplayed()));
-        onView(withId(R.id.chooser_nearby_button)).perform(click());
+        onView(withIdFromRuntimeResource("chooser_nearby_button")).check(matches(isDisplayed()));
+        onView(withIdFromRuntimeResource("chooser_nearby_button")).perform(click());
 
         ChooserActivityLoggerFake logger =
                 (ChooserActivityLoggerFake) activity.getChooserActivityLogger();
 
+        // TODO(b/211669337): Determine the expected SHARESHEET_DIRECT_LOAD_COMPLETE events.
+        logger.removeCallsForUiEventsOfType(
+                ChooserActivityLogger.SharesheetStandardEvent
+                        .SHARESHEET_DIRECT_LOAD_COMPLETE.getId());
+
         // SHARESHEET_TRIGGERED:
         assertThat(logger.event(0).getId(),
                 is(ChooserActivityLogger.SharesheetStandardEvent.SHARESHEET_TRIGGERED.getId()));
@@ -769,7 +794,8 @@
         assertThat(logger.get(1).atomId, is(FrameworkStatsLog.SHARESHEET_STARTED));
         assertThat(logger.get(1).intent, is(Intent.ACTION_SEND));
         assertThat(logger.get(1).mimeType, is("text/plain"));
-        assertThat(logger.get(1).packageName, is("com.android.frameworks.coretests"));
+        assertThat(logger.get(1).packageName, is(
+                InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageName()));
         assertThat(logger.get(1).appProvidedApp, is(0));
         assertThat(logger.get(1).appProvidedDirect, is(0));
         assertThat(logger.get(1).isWorkprofile, is(false));
@@ -780,31 +806,26 @@
                 is(ChooserActivityLogger
                         .SharesheetStandardEvent.SHARESHEET_APP_LOAD_COMPLETE.getId()));
 
-        // SHARESHEET_DIRECT_LOAD_COMPLETE:
+        // Next are just artifacts of test set-up:
         assertThat(logger.event(3).getId(),
                 is(ChooserActivityLogger
-                        .SharesheetStandardEvent.SHARESHEET_DIRECT_LOAD_COMPLETE.getId()));
-
-        // Fifth and sixth are just artifacts of test set-up:
-        assertThat(logger.event(4).getId(),
-                is(ChooserActivityLogger
                         .SharesheetStandardEvent.SHARESHEET_EMPTY_DIRECT_SHARE_ROW.getId()));
-        assertThat(logger.event(5).getId(),
+        assertThat(logger.event(4).getId(),
                 is(ChooserActivityLogger.SharesheetStandardEvent.SHARESHEET_EXPANDED.getId()));
 
-        // SHARESHEET_EDIT_TARGET_SELECTED:
-        assertThat(logger.get(6).atomId, is(FrameworkStatsLog.RANKING_SELECTED));
-        assertThat(logger.get(6).targetType,
+        // SHARESHEET_NEARBY_TARGET_SELECTED:
+        assertThat(logger.get(5).atomId, is(FrameworkStatsLog.RANKING_SELECTED));
+        assertThat(logger.get(5).targetType,
                 is(ChooserActivityLogger
                         .SharesheetTargetSelectedEvent.SHARESHEET_NEARBY_TARGET_SELECTED.getId()));
 
         // No more events.
-        assertThat(logger.numCalls(), is(7));
+        assertThat(logger.numCalls(), is(6));
     }
 
 
 
-    @Test
+    @Test @Ignore
     public void testEditImageLogs() throws Exception {
         Intent sendIntent = createSendImageIntent(
                 Uri.parse("android.resource://com.android.frameworks.coretests/"
@@ -824,12 +845,17 @@
                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
         waitForIdle();
 
-        onView(withId(R.id.chooser_edit_button)).check(matches(isDisplayed()));
-        onView(withId(R.id.chooser_edit_button)).perform(click());
+        onView(withIdFromRuntimeResource("chooser_edit_button")).check(matches(isDisplayed()));
+        onView(withIdFromRuntimeResource("chooser_edit_button")).perform(click());
 
         ChooserActivityLoggerFake logger =
                 (ChooserActivityLoggerFake) activity.getChooserActivityLogger();
 
+        // TODO(b/211669337): Determine the expected SHARESHEET_DIRECT_LOAD_COMPLETE events.
+        logger.removeCallsForUiEventsOfType(
+                ChooserActivityLogger.SharesheetStandardEvent
+                        .SHARESHEET_DIRECT_LOAD_COMPLETE.getId());
+
         // SHARESHEET_TRIGGERED:
         assertThat(logger.event(0).getId(),
                 is(ChooserActivityLogger.SharesheetStandardEvent.SHARESHEET_TRIGGERED.getId()));
@@ -838,7 +864,8 @@
         assertThat(logger.get(1).atomId, is(FrameworkStatsLog.SHARESHEET_STARTED));
         assertThat(logger.get(1).intent, is(Intent.ACTION_SEND));
         assertThat(logger.get(1).mimeType, is("image/png"));
-        assertThat(logger.get(1).packageName, is("com.android.frameworks.coretests"));
+        assertThat(logger.get(1).packageName, is(
+                InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageName()));
         assertThat(logger.get(1).appProvidedApp, is(0));
         assertThat(logger.get(1).appProvidedDirect, is(0));
         assertThat(logger.get(1).isWorkprofile, is(false));
@@ -849,26 +876,21 @@
                 is(ChooserActivityLogger
                         .SharesheetStandardEvent.SHARESHEET_APP_LOAD_COMPLETE.getId()));
 
-        // SHARESHEET_DIRECT_LOAD_COMPLETE:
+        // Next are just artifacts of test set-up:
         assertThat(logger.event(3).getId(),
                 is(ChooserActivityLogger
-                        .SharesheetStandardEvent.SHARESHEET_DIRECT_LOAD_COMPLETE.getId()));
-
-        // Fifth and sixth are just artifacts of test set-up:
-        assertThat(logger.event(4).getId(),
-                is(ChooserActivityLogger
                         .SharesheetStandardEvent.SHARESHEET_EMPTY_DIRECT_SHARE_ROW.getId()));
-        assertThat(logger.event(5).getId(),
+        assertThat(logger.event(4).getId(),
                 is(ChooserActivityLogger.SharesheetStandardEvent.SHARESHEET_EXPANDED.getId()));
 
         // SHARESHEET_EDIT_TARGET_SELECTED:
-        assertThat(logger.get(6).atomId, is(FrameworkStatsLog.RANKING_SELECTED));
-        assertThat(logger.get(6).targetType,
+        assertThat(logger.get(5).atomId, is(FrameworkStatsLog.RANKING_SELECTED));
+        assertThat(logger.get(5).targetType,
                 is(ChooserActivityLogger
                         .SharesheetTargetSelectedEvent.SHARESHEET_EDIT_TARGET_SELECTED.getId()));
 
         // No more events.
-        assertThat(logger.numCalls(), is(7));
+        assertThat(logger.numCalls(), is(6));
     }
 
 
@@ -897,10 +919,14 @@
                 .thenReturn(resolvedComponentInfos);
         mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
         waitForIdle();
-        onView(withId(R.id.content_preview_image_1_large)).check(matches(isDisplayed()));
-        onView(withId(R.id.content_preview_image_2_large)).check(matches(not(isDisplayed())));
-        onView(withId(R.id.content_preview_image_2_small)).check(matches(not(isDisplayed())));
-        onView(withId(R.id.content_preview_image_3_small)).check(matches(not(isDisplayed())));
+        onView(withIdFromRuntimeResource("content_preview_image_1_large"))
+                .check(matches(isDisplayed()));
+        onView(withIdFromRuntimeResource("content_preview_image_2_large"))
+                .check(matches(not(isDisplayed())));
+        onView(withIdFromRuntimeResource("content_preview_image_2_small"))
+                .check(matches(not(isDisplayed())));
+        onView(withIdFromRuntimeResource("content_preview_image_3_small"))
+                .check(matches(not(isDisplayed())));
     }
 
     @Test
@@ -929,10 +955,14 @@
                 .thenReturn(resolvedComponentInfos);
         mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
         waitForIdle();
-        onView(withId(R.id.content_preview_image_1_large)).check(matches(isDisplayed()));
-        onView(withId(R.id.content_preview_image_2_large)).check(matches(isDisplayed()));
-        onView(withId(R.id.content_preview_image_2_small)).check(matches(not(isDisplayed())));
-        onView(withId(R.id.content_preview_image_3_small)).check(matches(not(isDisplayed())));
+        onView(withIdFromRuntimeResource("content_preview_image_1_large"))
+                .check(matches(isDisplayed()));
+        onView(withIdFromRuntimeResource("content_preview_image_2_large"))
+                .check(matches(isDisplayed()));
+        onView(withIdFromRuntimeResource("content_preview_image_2_small"))
+                .check(matches(not(isDisplayed())));
+        onView(withIdFromRuntimeResource("content_preview_image_3_small"))
+                .check(matches(not(isDisplayed())));
     }
 
     @Test
@@ -964,10 +994,14 @@
                 .thenReturn(resolvedComponentInfos);
         mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
         waitForIdle();
-        onView(withId(R.id.content_preview_image_1_large)).check(matches(isDisplayed()));
-        onView(withId(R.id.content_preview_image_2_large)).check(matches(not(isDisplayed())));
-        onView(withId(R.id.content_preview_image_2_small)).check(matches(isDisplayed()));
-        onView(withId(R.id.content_preview_image_3_small)).check(matches(isDisplayed()));
+        onView(withIdFromRuntimeResource("content_preview_image_1_large"))
+                .check(matches(isDisplayed()));
+        onView(withIdFromRuntimeResource("content_preview_image_2_large"))
+                .check(matches(not(isDisplayed())));
+        onView(withIdFromRuntimeResource("content_preview_image_2_small"))
+                .check(matches(isDisplayed()));
+        onView(withIdFromRuntimeResource("content_preview_image_3_small"))
+                .check(matches(isDisplayed()));
     }
 
     @Test
@@ -1120,9 +1154,11 @@
                 .thenReturn(resolvedComponentInfos);
         mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
         waitForIdle();
-        onView(withId(R.id.content_preview_filename)).check(matches(isDisplayed()));
-        onView(withId(R.id.content_preview_filename)).check(matches(withText("app.pdf")));
-        onView(withId(R.id.content_preview_file_icon)).check(matches(isDisplayed()));
+        onView(withIdFromRuntimeResource("content_preview_filename")).check(matches(isDisplayed()));
+        onView(withIdFromRuntimeResource("content_preview_filename"))
+                .check(matches(withText("app.pdf")));
+        onView(withIdFromRuntimeResource("content_preview_file_icon"))
+                .check(matches(isDisplayed()));
     }
 
 
@@ -1150,9 +1186,12 @@
                 .thenReturn(resolvedComponentInfos);
         mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
         waitForIdle();
-        onView(withId(R.id.content_preview_filename)).check(matches(isDisplayed()));
-        onView(withId(R.id.content_preview_filename)).check(matches(withText("app.pdf + 2 files")));
-        onView(withId(R.id.content_preview_file_icon)).check(matches(isDisplayed()));
+        onView(withIdFromRuntimeResource("content_preview_filename"))
+                .check(matches(isDisplayed()));
+        onView(withIdFromRuntimeResource("content_preview_filename"))
+                .check(matches(withText("app.pdf + 2 files")));
+        onView(withIdFromRuntimeResource("content_preview_file_icon"))
+                .check(matches(isDisplayed()));
     }
 
     @Test
@@ -1179,9 +1218,11 @@
 
         mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
         waitForIdle();
-        onView(withId(R.id.content_preview_filename)).check(matches(isDisplayed()));
-        onView(withId(R.id.content_preview_filename)).check(matches(withText("app.pdf")));
-        onView(withId(R.id.content_preview_file_icon)).check(matches(isDisplayed()));
+        onView(withIdFromRuntimeResource("content_preview_filename")).check(matches(isDisplayed()));
+        onView(withIdFromRuntimeResource("content_preview_filename"))
+                .check(matches(withText("app.pdf")));
+        onView(withIdFromRuntimeResource("content_preview_file_icon"))
+                .check(matches(isDisplayed()));
     }
 
     @Test
@@ -1215,9 +1256,11 @@
 
         mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
         waitForIdle();
-        onView(withId(R.id.content_preview_filename)).check(matches(isDisplayed()));
-        onView(withId(R.id.content_preview_filename)).check(matches(withText("app.pdf + 1 file")));
-        onView(withId(R.id.content_preview_file_icon)).check(matches(isDisplayed()));
+        onView(withIdFromRuntimeResource("content_preview_filename")).check(matches(isDisplayed()));
+        onView(withIdFromRuntimeResource("content_preview_filename"))
+                .check(matches(withText("app.pdf + 1 file")));
+        onView(withIdFromRuntimeResource("content_preview_file_icon"))
+                .check(matches(isDisplayed()));
     }
 
     @Test
@@ -1290,13 +1333,20 @@
         } else {
             assertThat(activity.isAppPredictionServiceAvailable(), is(true));
 
+            if (!shouldTestTogglingAppPredictionServiceAvailabilityAtRuntime()) {
+                return;
+            }
+
             ChooserActivityOverrideData.getInstance().resources =
                     Mockito.spy(activity.getResources());
             when(
                     ChooserActivityOverrideData
                             .getInstance()
                             .resources
-                            .getString(R.string.config_defaultAppPredictionService))
+                            .getString(
+                                    getRuntimeResourceId(
+                                            "config_defaultAppPredictionService",
+                                            "string")))
                     .thenReturn("ComponentNameThatDoesNotExist");
 
             assertThat(activity.isAppPredictionServiceAvailable(), is(false));
@@ -1544,7 +1594,8 @@
                 ChooserActivityOverrideData
                         .getInstance()
                         .resources
-                        .getInteger(R.integer.config_maxShortcutTargetsPerApp))
+                        .getInteger(
+                              getRuntimeResourceId("config_maxShortcutTargetsPerApp", "integer")))
                 .thenReturn(1);
         Intent sendIntent = createSendTextIntent();
         // We need app targets for direct targets to get displayed
@@ -1615,7 +1666,8 @@
                 ChooserActivityOverrideData
                         .getInstance()
                         .resources
-                        .getInteger(R.integer.config_maxShortcutTargetsPerApp))
+                        .getInteger(
+                              getRuntimeResourceId("config_maxShortcutTargetsPerApp", "integer")))
                 .thenReturn(1);
         Intent sendIntent = createSendTextIntent();
         // We need app targets for direct targets to get displayed
@@ -1787,7 +1839,7 @@
         mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
         waitForIdle();
 
-        onView(withId(R.id.tabs)).check(matches(isDisplayed()));
+        onView(withIdFromRuntimeResource("tabs")).check(matches(isDisplayed()));
     }
 
     @Test
@@ -1800,7 +1852,7 @@
         mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
         waitForIdle();
 
-        onView(withId(R.id.tabs)).check(matches(not(isDisplayed())));
+        onView(withIdFromRuntimeResource("tabs")).check(matches(not(isDisplayed())));
     }
 
     @Test
@@ -1825,7 +1877,7 @@
         waitForIdle();
 
         assertThat(activity.getCurrentUserHandle().getIdentifier(), is(0));
-        onView(withText(R.string.resolver_work_tab)).perform(click());
+        onView(withTextFromRuntimeResource("resolver_work_tab")).perform(click());
         assertThat(activity.getCurrentUserHandle().getIdentifier(), is(10));
         assertThat(activity.getPersonalListAdapter().getCount(), is(personalProfileTargets));
         assertThat(activity.getWorkListAdapter().getCount(), is(workProfileTargets));
@@ -1848,7 +1900,7 @@
         final IChooserWrapper activity = (IChooserWrapper)
                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
         waitForIdle();
-        onView(withText(R.string.resolver_work_tab)).perform(click());
+        onView(withTextFromRuntimeResource("resolver_work_tab")).perform(click());
         waitForIdle();
 
         assertThat(activity.getWorkListAdapter().getCount(), is(workProfileTargets));
@@ -1875,7 +1927,7 @@
 
         mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
         waitForIdle();
-        onView(withText(R.string.resolver_work_tab)).perform(click());
+        onView(withTextFromRuntimeResource("resolver_work_tab")).perform(click());
         waitForIdle();
         // wait for the share sheet to expand
         Thread.sleep(ChooserActivity.LIST_VIEW_UPDATE_INTERVAL_IN_MILLIS);
@@ -1906,12 +1958,12 @@
 
         mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
         waitForIdle();
-        onView(withText(R.string.resolver_work_tab)).perform(click());
+        onView(withTextFromRuntimeResource("resolver_work_tab")).perform(click());
         waitForIdle();
-        onView(withId(R.id.contentPanel))
+        onView(withIdFromRuntimeResource("contentPanel"))
                 .perform(swipeUp());
 
-        onView(withText(R.string.resolver_cross_profile_blocked))
+        onView(withTextFromRuntimeResource("resolver_cross_profile_blocked"))
                 .check(matches(isDisplayed()));
     }
 
@@ -1932,12 +1984,12 @@
         ResolverActivity.ENABLE_TABBED_VIEW = true;
         mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
         waitForIdle();
-        onView(withId(R.id.contentPanel))
+        onView(withIdFromRuntimeResource("contentPanel"))
                 .perform(swipeUp());
-        onView(withText(R.string.resolver_work_tab)).perform(click());
+        onView(withTextFromRuntimeResource("resolver_work_tab")).perform(click());
         waitForIdle();
 
-        onView(withText(R.string.resolver_turn_on_work_apps))
+        onView(withTextFromRuntimeResource("resolver_turn_on_work_apps"))
                 .check(matches(isDisplayed()));
     }
 
@@ -1956,12 +2008,12 @@
 
         mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
         waitForIdle();
-        onView(withId(R.id.contentPanel))
+        onView(withIdFromRuntimeResource("contentPanel"))
                 .perform(swipeUp());
-        onView(withText(R.string.resolver_work_tab)).perform(click());
+        onView(withTextFromRuntimeResource("resolver_work_tab")).perform(click());
         waitForIdle();
 
-        onView(withText(R.string.resolver_no_work_apps_available))
+        onView(withTextFromRuntimeResource("resolver_no_work_apps_available"))
                 .check(matches(isDisplayed()));
     }
 
@@ -1982,12 +2034,12 @@
 
         mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
         waitForIdle();
-        onView(withId(R.id.contentPanel))
+        onView(withIdFromRuntimeResource("contentPanel"))
                 .perform(swipeUp());
-        onView(withText(R.string.resolver_work_tab)).perform(click());
+        onView(withTextFromRuntimeResource("resolver_work_tab")).perform(click());
         waitForIdle();
 
-        onView(withText(R.string.resolver_cross_profile_blocked))
+        onView(withTextFromRuntimeResource("resolver_cross_profile_blocked"))
                 .check(matches(isDisplayed()));
     }
 
@@ -2007,12 +2059,12 @@
 
         mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
         waitForIdle();
-        onView(withId(R.id.contentPanel))
+        onView(withIdFromRuntimeResource("contentPanel"))
                 .perform(swipeUp());
-        onView(withText(R.string.resolver_work_tab)).perform(click());
+        onView(withTextFromRuntimeResource("resolver_work_tab")).perform(click());
         waitForIdle();
 
-        onView(withText(R.string.resolver_no_work_apps_available))
+        onView(withTextFromRuntimeResource("resolver_no_work_apps_available"))
                 .check(matches(isDisplayed()));
     }
 
@@ -2036,7 +2088,7 @@
         waitForIdle();
 
         assertThat(activity.getAdapter().getCount(), is(2));
-        onView(withId(R.id.profile_button)).check(doesNotExist());
+        onView(withIdFromRuntimeResource("profile_button")).check(doesNotExist());
 
         ResolveInfo[] chosen = new ResolveInfo[1];
         ChooserActivityOverrideData.getInstance().onSafelyStartCallback = targetInfo -> {
@@ -2052,6 +2104,11 @@
         ChooserActivityLoggerFake logger =
                 (ChooserActivityLoggerFake) activity.getChooserActivityLogger();
 
+        // TODO(b/211669337): Determine the expected SHARESHEET_DIRECT_LOAD_COMPLETE events.
+        logger.removeCallsForUiEventsOfType(
+                ChooserActivityLogger.SharesheetStandardEvent
+                        .SHARESHEET_DIRECT_LOAD_COMPLETE.getId());
+
         // SHARESHEET_TRIGGERED:
         assertThat(logger.event(0).getId(),
                 is(ChooserActivityLogger.SharesheetStandardEvent.SHARESHEET_TRIGGERED.getId()));
@@ -2060,7 +2117,8 @@
         assertThat(logger.get(1).atomId, is(FrameworkStatsLog.SHARESHEET_STARTED));
         assertThat(logger.get(1).intent, is(Intent.ACTION_SEND));
         assertThat(logger.get(1).mimeType, is("text/plain"));
-        assertThat(logger.get(1).packageName, is("com.android.frameworks.coretests"));
+        assertThat(logger.get(1).packageName, is(
+                InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageName()));
         assertThat(logger.get(1).appProvidedApp, is(0));
         assertThat(logger.get(1).appProvidedDirect, is(0));
         assertThat(logger.get(1).isWorkprofile, is(false));
@@ -2071,26 +2129,21 @@
                 is(ChooserActivityLogger
                         .SharesheetStandardEvent.SHARESHEET_APP_LOAD_COMPLETE.getId()));
 
-        // SHARESHEET_DIRECT_LOAD_COMPLETE:
+        // Next are just artifacts of test set-up:
         assertThat(logger.event(3).getId(),
                 is(ChooserActivityLogger
-                        .SharesheetStandardEvent.SHARESHEET_DIRECT_LOAD_COMPLETE.getId()));
-
-        // Fifth and sixth are just artifacts of test set-up:
-        assertThat(logger.event(4).getId(),
-                is(ChooserActivityLogger
                         .SharesheetStandardEvent.SHARESHEET_EMPTY_DIRECT_SHARE_ROW.getId()));
-        assertThat(logger.event(5).getId(),
+        assertThat(logger.event(4).getId(),
                 is(ChooserActivityLogger.SharesheetStandardEvent.SHARESHEET_EXPANDED.getId()));
 
-        // SHARESHEET_EDIT_TARGET_SELECTED:
-        assertThat(logger.get(6).atomId, is(FrameworkStatsLog.RANKING_SELECTED));
-        assertThat(logger.get(6).targetType,
+        // SHARESHEET_APP_TARGET_SELECTED:
+        assertThat(logger.get(5).atomId, is(FrameworkStatsLog.RANKING_SELECTED));
+        assertThat(logger.get(5).targetType,
                 is(ChooserActivityLogger
                         .SharesheetTargetSelectedEvent.SHARESHEET_APP_TARGET_SELECTED.getId()));
 
         // No more events.
-        assertThat(logger.numCalls(), is(7));
+        assertThat(logger.numCalls(), is(6));
     }
 
     @Test @Ignore
@@ -2161,7 +2214,8 @@
         assertThat(logger.get(1).atomId, is(FrameworkStatsLog.SHARESHEET_STARTED));
         assertThat(logger.get(1).intent, is(Intent.ACTION_SEND));
         assertThat(logger.get(1).mimeType, is("text/plain"));
-        assertThat(logger.get(1).packageName, is("com.android.frameworks.coretests"));
+        assertThat(logger.get(1).packageName, is(
+                InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageName()));
         assertThat(logger.get(1).appProvidedApp, is(0));
         assertThat(logger.get(1).appProvidedDirect, is(0));
         assertThat(logger.get(1).isWorkprofile, is(false));
@@ -2179,7 +2233,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
@@ -2210,6 +2264,11 @@
         ChooserActivityLoggerFake logger =
                 (ChooserActivityLoggerFake) activity.getChooserActivityLogger();
 
+        // TODO(b/211669337): Determine the expected SHARESHEET_DIRECT_LOAD_COMPLETE events.
+        logger.removeCallsForUiEventsOfType(
+                ChooserActivityLogger.SharesheetStandardEvent
+                        .SHARESHEET_DIRECT_LOAD_COMPLETE.getId());
+
         // SHARESHEET_TRIGGERED:
         assertThat(logger.event(0).getId(),
                 is(ChooserActivityLogger.SharesheetStandardEvent.SHARESHEET_TRIGGERED.getId()));
@@ -2218,7 +2277,8 @@
         assertThat(logger.get(1).atomId, is(FrameworkStatsLog.SHARESHEET_STARTED));
         assertThat(logger.get(1).intent, is(Intent.ACTION_SEND));
         assertThat(logger.get(1).mimeType, is("text/plain"));
-        assertThat(logger.get(1).packageName, is("com.android.frameworks.coretests"));
+        assertThat(logger.get(1).packageName, is(
+                InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageName()));
         assertThat(logger.get(1).appProvidedApp, is(0));
         assertThat(logger.get(1).appProvidedDirect, is(0));
         assertThat(logger.get(1).isWorkprofile, is(false));
@@ -2229,21 +2289,16 @@
                 is(ChooserActivityLogger
                         .SharesheetStandardEvent.SHARESHEET_APP_LOAD_COMPLETE.getId()));
 
-        // SHARESHEET_DIRECT_LOAD_COMPLETE:
-        assertThat(logger.event(3).getId(),
-                is(ChooserActivityLogger
-                        .SharesheetStandardEvent.SHARESHEET_DIRECT_LOAD_COMPLETE.getId()));
-
         // SHARESHEET_EMPTY_DIRECT_SHARE_ROW:
-        assertThat(logger.event(4).getId(),
+        assertThat(logger.event(3).getId(),
                 is(ChooserActivityLogger
                         .SharesheetStandardEvent.SHARESHEET_EMPTY_DIRECT_SHARE_ROW.getId()));
 
-        // Sixth is just an artifact of test set-up:
-        assertThat(logger.event(5).getId(),
+        // Next is just an artifact of test set-up:
+        assertThat(logger.event(4).getId(),
                 is(ChooserActivityLogger.SharesheetStandardEvent.SHARESHEET_EXPANDED.getId()));
 
-        assertThat(logger.numCalls(), is(6));
+        assertThat(logger.numCalls(), is(5));
     }
 
     @Test
@@ -2265,12 +2320,17 @@
                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
         waitForIdle();
 
-        onView(withId(R.id.chooser_copy_button)).check(matches(isDisplayed()));
-        onView(withId(R.id.chooser_copy_button)).perform(click());
+        onView(withIdFromRuntimeResource("chooser_copy_button")).check(matches(isDisplayed()));
+        onView(withIdFromRuntimeResource("chooser_copy_button")).perform(click());
 
         ChooserActivityLoggerFake logger =
                 (ChooserActivityLoggerFake) activity.getChooserActivityLogger();
 
+        // TODO(b/211669337): Determine the expected SHARESHEET_DIRECT_LOAD_COMPLETE events.
+        logger.removeCallsForUiEventsOfType(
+                ChooserActivityLogger.SharesheetStandardEvent
+                        .SHARESHEET_DIRECT_LOAD_COMPLETE.getId());
+
         // SHARESHEET_TRIGGERED:
         assertThat(logger.event(0).getId(),
                 is(ChooserActivityLogger.SharesheetStandardEvent.SHARESHEET_TRIGGERED.getId()));
@@ -2279,7 +2339,8 @@
         assertThat(logger.get(1).atomId, is(FrameworkStatsLog.SHARESHEET_STARTED));
         assertThat(logger.get(1).intent, is(Intent.ACTION_SEND));
         assertThat(logger.get(1).mimeType, is("text/plain"));
-        assertThat(logger.get(1).packageName, is("com.android.frameworks.coretests"));
+        assertThat(logger.get(1).packageName, is(
+                InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageName()));
         assertThat(logger.get(1).appProvidedApp, is(0));
         assertThat(logger.get(1).appProvidedDirect, is(0));
         assertThat(logger.get(1).isWorkprofile, is(false));
@@ -2290,26 +2351,21 @@
                 is(ChooserActivityLogger
                         .SharesheetStandardEvent.SHARESHEET_APP_LOAD_COMPLETE.getId()));
 
-        // SHARESHEET_DIRECT_LOAD_COMPLETE:
+        // Next are just artifacts of test set-up:
         assertThat(logger.event(3).getId(),
                 is(ChooserActivityLogger
-                        .SharesheetStandardEvent.SHARESHEET_DIRECT_LOAD_COMPLETE.getId()));
-
-        // Fifth and sixth are just artifacts of test set-up:
-        assertThat(logger.event(4).getId(),
-                is(ChooserActivityLogger
                         .SharesheetStandardEvent.SHARESHEET_EMPTY_DIRECT_SHARE_ROW.getId()));
-        assertThat(logger.event(5).getId(),
+        assertThat(logger.event(4).getId(),
                 is(ChooserActivityLogger.SharesheetStandardEvent.SHARESHEET_EXPANDED.getId()));
 
-        // SHARESHEET_EDIT_TARGET_SELECTED:
-        assertThat(logger.get(6).atomId, is(FrameworkStatsLog.RANKING_SELECTED));
-        assertThat(logger.get(6).targetType,
+        // SHARESHEET_COPY_TARGET_SELECTED:
+        assertThat(logger.get(5).atomId, is(FrameworkStatsLog.RANKING_SELECTED));
+        assertThat(logger.get(5).targetType,
                 is(ChooserActivityLogger
                         .SharesheetTargetSelectedEvent.SHARESHEET_COPY_TARGET_SELECTED.getId()));
 
         // No more events.
-        assertThat(logger.numCalls(), is(7));
+        assertThat(logger.numCalls(), is(6));
     }
 
     @Test
@@ -2329,14 +2385,19 @@
         final IChooserWrapper activity = (IChooserWrapper)
                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
         waitForIdle();
-        onView(withText(R.string.resolver_work_tab)).perform(click());
+        onView(withTextFromRuntimeResource("resolver_work_tab")).perform(click());
         waitForIdle();
-        onView(withText(R.string.resolver_personal_tab)).perform(click());
+        onView(withTextFromRuntimeResource("resolver_personal_tab")).perform(click());
         waitForIdle();
 
         ChooserActivityLoggerFake logger =
                 (ChooserActivityLoggerFake) activity.getChooserActivityLogger();
 
+        // TODO(b/211669337): Determine the expected SHARESHEET_DIRECT_LOAD_COMPLETE events.
+        logger.removeCallsForUiEventsOfType(
+                ChooserActivityLogger.SharesheetStandardEvent
+                        .SHARESHEET_DIRECT_LOAD_COMPLETE.getId());
+
         // SHARESHEET_TRIGGERED:
         assertThat(logger.event(0).getId(),
                 is(ChooserActivityLogger.SharesheetStandardEvent.SHARESHEET_TRIGGERED.getId()));
@@ -2345,7 +2406,8 @@
         assertThat(logger.get(1).atomId, is(FrameworkStatsLog.SHARESHEET_STARTED));
         assertThat(logger.get(1).intent, is(Intent.ACTION_SEND));
         assertThat(logger.get(1).mimeType, is(TEST_MIME_TYPE));
-        assertThat(logger.get(1).packageName, is("com.android.frameworks.coretests"));
+        assertThat(logger.get(1).packageName, is(
+                InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageName()));
         assertThat(logger.get(1).appProvidedApp, is(0));
         assertThat(logger.get(1).appProvidedDirect, is(0));
         assertThat(logger.get(1).isWorkprofile, is(false));
@@ -2356,45 +2418,35 @@
                 is(ChooserActivityLogger
                         .SharesheetStandardEvent.SHARESHEET_APP_LOAD_COMPLETE.getId()));
 
-        // SHARESHEET_DIRECT_LOAD_COMPLETE:
+        // Next is just an artifact of test set-up:
         assertThat(logger.event(3).getId(),
                 is(ChooserActivityLogger
-                        .SharesheetStandardEvent.SHARESHEET_DIRECT_LOAD_COMPLETE.getId()));
-
-        // Fifth is just an artifact of test set-up:
-        assertThat(logger.event(4).getId(),
-                is(ChooserActivityLogger
                         .SharesheetStandardEvent.SHARESHEET_EMPTY_DIRECT_SHARE_ROW.getId()));
 
         // SHARESHEET_PROFILE_CHANGED:
-        assertThat(logger.event(5).getId(),
+        assertThat(logger.event(4).getId(),
                 is(ChooserActivityLogger.SharesheetStandardEvent
                         .SHARESHEET_PROFILE_CHANGED.getId()));
 
         // Repeat the loading steps in the new profile:
 
         // SHARESHEET_APP_LOAD_COMPLETE:
-        assertThat(logger.event(6).getId(),
+        assertThat(logger.event(5).getId(),
                 is(ChooserActivityLogger
                         .SharesheetStandardEvent.SHARESHEET_APP_LOAD_COMPLETE.getId()));
 
-        // SHARESHEET_DIRECT_LOAD_COMPLETE:
-        assertThat(logger.event(7).getId(),
-                is(ChooserActivityLogger
-                        .SharesheetStandardEvent.SHARESHEET_DIRECT_LOAD_COMPLETE.getId()));
-
-        // Ninth is again an artifact of test set-up:
-        assertThat(logger.event(8).getId(),
+        // Next is again an artifact of test set-up:
+        assertThat(logger.event(6).getId(),
                 is(ChooserActivityLogger
                         .SharesheetStandardEvent.SHARESHEET_EMPTY_DIRECT_SHARE_ROW.getId()));
 
         // SHARESHEET_PROFILE_CHANGED:
-        assertThat(logger.event(9).getId(),
+        assertThat(logger.event(7).getId(),
                 is(ChooserActivityLogger.SharesheetStandardEvent
                         .SHARESHEET_PROFILE_CHANGED.getId()));
 
         // No more events (this profile was already loaded).
-        assertThat(logger.numCalls(), is(10));
+        assertThat(logger.numCalls(), is(8));
     }
 
     @Test
@@ -2576,12 +2628,12 @@
 
         mActivityRule.launchActivity(chooserIntent);
         waitForIdle();
-        onView(withText(R.string.resolver_work_tab)).perform(click());
+        onView(withTextFromRuntimeResource("resolver_work_tab")).perform(click());
         waitForIdle();
-        onView(withId(R.id.contentPanel))
+        onView(withIdFromRuntimeResource("contentPanel"))
                 .perform(swipeUp());
 
-        onView(withText(R.string.resolver_cross_profile_blocked))
+        onView(withTextFromRuntimeResource("resolver_cross_profile_blocked"))
                 .check(matches(isDisplayed()));
     }
 
@@ -2610,12 +2662,12 @@
 
         mActivityRule.launchActivity(chooserIntent);
         waitForIdle();
-        onView(withId(R.id.contentPanel))
+        onView(withIdFromRuntimeResource("contentPanel"))
                 .perform(swipeUp());
-        onView(withText(R.string.resolver_work_tab)).perform(click());
+        onView(withTextFromRuntimeResource("resolver_work_tab")).perform(click());
         waitForIdle();
 
-        onView(withText(R.string.resolver_no_work_apps_available))
+        onView(withTextFromRuntimeResource("resolver_no_work_apps_available"))
                 .check(matches(isDisplayed()));
     }
 
@@ -2675,9 +2727,9 @@
 
         mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
         waitForIdle();
-        onView(withId(R.id.contentPanel))
+        onView(withIdFromRuntimeResource("contentPanel"))
                 .perform(swipeUp());
-        onView(withText(R.string.resolver_work_tab)).perform(click());
+        onView(withTextFromRuntimeResource("resolver_work_tab")).perform(click());
         waitForIdle();
 
         assertFalse("Direct share targets were queried on a paused work profile",
@@ -2707,9 +2759,9 @@
 
         mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
         waitForIdle();
-        onView(withId(R.id.contentPanel))
+        onView(withIdFromRuntimeResource("contentPanel"))
                 .perform(swipeUp());
-        onView(withText(R.string.resolver_work_tab)).perform(click());
+        onView(withTextFromRuntimeResource("resolver_work_tab")).perform(click());
         waitForIdle();
 
         assertFalse("Direct share targets were queried on a locked work profile user",
@@ -2734,9 +2786,8 @@
                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
         final IChooserWrapper wrapper = (IChooserWrapper) activity;
         waitForIdle();
-        onView(withId(R.id.contentPanel))
-                .perform(swipeUp());
-        onView(withText(R.string.resolver_work_tab)).perform(click());
+        onView(withIdFromRuntimeResource("contentPanel")).perform(swipeUp());
+        onView(withTextFromRuntimeResource("resolver_work_tab")).perform(click());
         waitForIdle();
 
         assertEquals(3, wrapper.getWorkListAdapter().getCount());
@@ -2765,9 +2816,9 @@
 
         mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
         waitForIdle();
-        onView(withId(R.id.contentPanel))
+        onView(withIdFromRuntimeResource("contentPanel"))
                 .perform(swipeUp());
-        onView(withText(R.string.resolver_work_tab)).perform(click());
+        onView(withTextFromRuntimeResource("resolver_work_tab")).perform(click());
         waitForIdle();
 
         assertFalse("Direct share targets were queried on a locked work profile user",
@@ -2792,9 +2843,9 @@
                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
         final IChooserWrapper wrapper = (IChooserWrapper) activity;
         waitForIdle();
-        onView(withId(R.id.contentPanel))
+        onView(withIdFromRuntimeResource("contentPanel"))
                 .perform(swipeUp());
-        onView(withText(R.string.resolver_work_tab)).perform(click());
+        onView(withTextFromRuntimeResource("resolver_work_tab")).perform(click());
         waitForIdle();
 
         assertEquals(3, wrapper.getWorkListAdapter().getCount());
@@ -3043,4 +3094,27 @@
                                 eq(UserHandle.SYSTEM)))
                 .thenReturn(new ArrayList<>(personalResolvedComponentInfos));
     }
+
+    private Matcher<View> withIdFromRuntimeResource(String id) {
+        return withId(getRuntimeResourceId(id, "id"));
+    }
+
+    private Matcher<View> withTextFromRuntimeResource(String id) {
+        return withText(getRuntimeResourceId(id, "string"));
+    }
+
+    // ChooserWrapperActivity inherits from the framework ChooserActivity, so if the framework
+    // resources have been updated since the framework was last built/pushed, the inherited behavior
+    // (which is the focus of our testing) will still be implemented in terms of the old resource
+    // IDs; then when we try to assert those IDs in tests (e.g. `onView(withText(R.string.foo))`),
+    // the expected values won't match. The tests can instead call this method (with the same
+    // general semantics as Resources#getIdentifier() e.g. `getRuntimeResourceId("foo", "string")`)
+    // to refer to the resource by that name in the runtime chooser, regardless of whether the
+    // framework code on the device is up-to-date.
+    // TODO: is there a better way to do this? (Other than abandoning inheritance-based DI wrapper?)
+    private int getRuntimeResourceId(String name, String defType) {
+        int id = mActivityRule.getActivity().getResources().getIdentifier(name, defType, "android");
+        assertThat(id, greaterThan(0));
+        return id;
+    }
 }
diff --git a/core/tests/coretests/src/com/android/internal/content/res/OverlayConfigTest.java b/core/tests/coretests/src/com/android/internal/content/res/OverlayConfigTest.java
index aea453e..caec365 100644
--- a/core/tests/coretests/src/com/android/internal/content/res/OverlayConfigTest.java
+++ b/core/tests/coretests/src/com/android/internal/content/res/OverlayConfigTest.java
@@ -24,6 +24,7 @@
 
 import android.os.FileUtils;
 import android.os.SystemProperties;
+import android.platform.test.annotations.Presubmit;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
@@ -46,6 +47,7 @@
 import java.io.InputStream;
 import java.util.ArrayList;
 
+@Presubmit
 @RunWith(AndroidJUnit4.class)
 public class OverlayConfigTest {
     private static final String TEST_APK_PACKAGE_NAME =
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsImplTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsImplTest.java
index c1a45c4..388cf6e 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsImplTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsImplTest.java
@@ -22,6 +22,8 @@
 import static android.os.BatteryStats.Uid.PROCESS_STATE_FOREGROUND_SERVICE;
 import static android.os.BatteryStats.Uid.PROCESS_STATE_TOP;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -36,6 +38,7 @@
 
 import android.app.ActivityManager;
 import android.os.BatteryStats;
+import android.os.WakeLockStats;
 import android.util.SparseArray;
 import android.view.Display;
 
@@ -50,6 +53,8 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.util.List;
+
 @LargeTest
 @RunWith(AndroidJUnit4.class)
 @SuppressWarnings("GuardedBy")
@@ -507,4 +512,51 @@
         final BatteryStatsImpl.Uid u = mBatteryStatsImpl.getUidStatsLocked(parentUid);
         u.addIsolatedUid(childUid);
     }
+
+    @Test
+    public void testGetWakeLockStats() {
+        mBatteryStatsImpl.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
+
+        // First wakelock, acquired once, not currently held
+        mMockClock.realtime = 1000;
+        mBatteryStatsImpl.noteStartWakeLocked(10100, 100, null, "wakeLock1", null,
+                BatteryStats.WAKE_TYPE_PARTIAL, false);
+
+        mMockClock.realtime = 3000;
+        mBatteryStatsImpl.noteStopWakeLocked(10100, 100, null, "wakeLock1", null,
+                BatteryStats.WAKE_TYPE_PARTIAL);
+
+        // Second wakelock, acquired twice, still held
+        mMockClock.realtime = 4000;
+        mBatteryStatsImpl.noteStartWakeLocked(10200, 101, null, "wakeLock2", null,
+                BatteryStats.WAKE_TYPE_PARTIAL, false);
+
+        mMockClock.realtime = 5000;
+        mBatteryStatsImpl.noteStopWakeLocked(10200, 101, null, "wakeLock2", null,
+                BatteryStats.WAKE_TYPE_PARTIAL);
+
+        mMockClock.realtime = 6000;
+        mBatteryStatsImpl.noteStartWakeLocked(10200, 101, null, "wakeLock2", null,
+                BatteryStats.WAKE_TYPE_PARTIAL, false);
+
+        mMockClock.realtime = 9000;
+
+        List<WakeLockStats.WakeLock> wakeLockStats =
+                mBatteryStatsImpl.getWakeLockStats().getWakeLocks();
+        assertThat(wakeLockStats).hasSize(2);
+
+        WakeLockStats.WakeLock wakeLock1 = wakeLockStats.stream()
+                .filter(wl -> wl.uid == 10100 && wl.name.equals("wakeLock1")).findFirst().get();
+
+        assertThat(wakeLock1.timesAcquired).isEqualTo(1);
+        assertThat(wakeLock1.timeHeldMs).isEqualTo(0);  // Not currently held
+        assertThat(wakeLock1.totalTimeHeldMs).isEqualTo(2000); // 3000-1000
+
+        WakeLockStats.WakeLock wakeLock2 = wakeLockStats.stream()
+                .filter(wl -> wl.uid == 10200 && wl.name.equals("wakeLock2")).findFirst().get();
+
+        assertThat(wakeLock2.timesAcquired).isEqualTo(2);
+        assertThat(wakeLock2.timeHeldMs).isEqualTo(3000);  // 9000-6000
+        assertThat(wakeLock2.totalTimeHeldMs).isEqualTo(4000); // (5000-4000) + (9000-6000)
+    }
 }
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 7db31fb..9b3876f 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsProviderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsProviderTest.java
@@ -39,6 +39,8 @@
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import libcore.testing.io.TestIoUtils;
+
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -52,9 +54,12 @@
     private static final int APP_UID = Process.FIRST_APPLICATION_UID + 42;
     private static final long MINUTE_IN_MS = 60 * 1000;
 
+    private final File mHistoryDir =
+            TestIoUtils.createTemporaryDirectory(getClass().getSimpleName());
     @Rule
-    public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule(12345)
-            .setAveragePower(PowerProfile.POWER_FLASHLIGHT, 360.0);
+    public final BatteryUsageStatsRule mStatsRule =
+            new BatteryUsageStatsRule(12345, mHistoryDir)
+                    .setAveragePower(PowerProfile.POWER_FLASHLIGHT, 360.0);
 
     @Test
     public void test_getBatteryUsageStats() {
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java
index f75a6df..b3056e2 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java
@@ -40,6 +40,7 @@
 import org.junit.runners.model.Statement;
 import org.mockito.stubbing.Answer;
 
+import java.io.File;
 import java.util.Arrays;
 
 public class BatteryUsageStatsRule implements TestRule {
@@ -57,14 +58,18 @@
     private boolean mScreenOn;
 
     public BatteryUsageStatsRule() {
-        this(0);
+        this(0, null);
     }
 
     public BatteryUsageStatsRule(long currentTime) {
+        this(currentTime, null);
+    }
+
+    public BatteryUsageStatsRule(long currentTime, File historyDir) {
         Context context = InstrumentationRegistry.getContext();
         mPowerProfile = spy(new PowerProfile(context, true /* forTest */));
         mMockClock.currentTime = currentTime;
-        mBatteryStats = new MockBatteryStatsImpl(mMockClock);
+        mBatteryStats = new MockBatteryStatsImpl(mMockClock, historyDir);
         mBatteryStats.setPowerProfile(mPowerProfile);
         mBatteryStats.onSystemReady();
     }
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 0b8dc3f..92fca36 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -223,6 +223,10 @@
                       targetSdk="29">
         <new-permission name="android.permission.ACCESS_BACKGROUND_LOCATION" />
     </split-permission>
+    <split-permission name="android.permission.BODY_SENSORS"
+                      targetSdk="33">
+        <new-permission name="android.permission.BODY_SENSORS_BACKGROUND" />
+    </split-permission>
     <split-permission name="android.permission.READ_EXTERNAL_STORAGE"
                       targetSdk="29">
         <new-permission name="android.permission.ACCESS_MEDIA_LOCATION" />
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index e61a665..f17fa3b 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -520,6 +520,8 @@
         <permission name="android.permission.LOCK_DEVICE" />
         <!-- Permission required for CTS test - CtsSafetyCenterTestCases -->
         <permission name="android.permission.SEND_SAFETY_CENTER_UPDATE" />
+        <!-- Permission required for CTS test - CtsSafetyCenterTestCases -->
+        <permission name="android.permission.READ_SAFETY_CENTER_STATUS" />
         <!-- Permission required for CTS test - CommunalManagerTest -->
         <permission name="android.permission.WRITE_COMMUNAL_STATE" />
         <permission name="android.permission.READ_COMMUNAL_STATE" />
diff --git a/graphics/java/android/graphics/BLASTBufferQueue.java b/graphics/java/android/graphics/BLASTBufferQueue.java
index 8d3eadb..a9e730d 100644
--- a/graphics/java/android/graphics/BLASTBufferQueue.java
+++ b/graphics/java/android/graphics/BLASTBufferQueue.java
@@ -27,8 +27,6 @@
     // Note: This field is accessed by native code.
     public long mNativeObject; // BLASTBufferQueue*
 
-    private static native long nativeCreateAndUpdate(String name, long surfaceControl, long width,
-            long height, int format);
     private static native long nativeCreate(String name);
     private static native void nativeDestroy(long ptr);
     private static native Surface nativeGetSurface(long ptr, boolean includeSurfaceControlHandle);
@@ -40,11 +38,13 @@
                                                               long frameNumber);
     private static native long nativeGetLastAcquiredFrameNum(long ptr);
     private static native void nativeApplyPendingTransactions(long ptr, long frameNumber);
+    private static native boolean nativeIsSameSurfaceControl(long ptr, long surfaceControlPtr);
 
     /** Create a new connection with the surface flinger. */
     public BLASTBufferQueue(String name, SurfaceControl sc, int width, int height,
             @PixelFormat.Format int format) {
-        mNativeObject = nativeCreateAndUpdate(name, sc.mNativeObject, width, height, format);
+        this(name);
+        update(sc, width, height, format);
     }
 
     public BLASTBufferQueue(String name) {
@@ -152,4 +152,11 @@
     public long getLastAcquiredFrameNum() {
         return nativeGetLastAcquiredFrameNum(mNativeObject);
     }
+
+    /**
+     * @return True if the associated SurfaceControl has the same handle as {@param sc}.
+     */
+    public boolean isSameSurfaceControl(SurfaceControl sc) {
+        return nativeIsSameSurfaceControl(mNativeObject, sc.mNativeObject);
+    }
 }
diff --git a/graphics/java/android/graphics/HardwareRenderer.java b/graphics/java/android/graphics/HardwareRenderer.java
index 2b18350..fd4bed1 100644
--- a/graphics/java/android/graphics/HardwareRenderer.java
+++ b/graphics/java/android/graphics/HardwareRenderer.java
@@ -902,6 +902,20 @@
          * @param frame The id of the frame being drawn.
          */
         void onFrameDraw(long frame);
+
+        /**
+         * Invoked during a frame drawing.
+         *
+         * @param syncResult The result of the draw. Should be a value or a combination of values
+         *                   from {@link SyncAndDrawResult}
+         * @param frame The id of the frame being drawn.
+         *
+         * @return A {@link FrameCommitCallback} that will report back if the current vsync draws.
+         */
+        default FrameCommitCallback onFrameDraw(@SyncAndDrawResult int syncResult, long frame) {
+            onFrameDraw(frame);
+            return null;
+        }
     }
 
     /**
diff --git a/graphics/java/android/graphics/Outline.java b/graphics/java/android/graphics/Outline.java
index b77865f..fc7f84c 100644
--- a/graphics/java/android/graphics/Outline.java
+++ b/graphics/java/android/graphics/Outline.java
@@ -118,13 +118,13 @@
     /**
      * Returns whether the outline can be used to clip a View.
      * <p>
-     * Currently, only Outlines that can be represented as a rectangle, circle,
-     * or round rect support clipping.
+     * As of API 33, all Outline shapes support clipping. Prior to API 33, only Outlines that
+     * could be represented as a rectangle, circle, or round rect supported clipping.
      *
      * @see android.view.View#setClipToOutline(boolean)
      */
     public boolean canClip() {
-        return mMode != MODE_PATH;
+        return true;
     }
 
     /**
diff --git a/graphics/java/android/graphics/RenderEffect.java b/graphics/java/android/graphics/RenderEffect.java
index ad4c3fe..b8a4685 100644
--- a/graphics/java/android/graphics/RenderEffect.java
+++ b/graphics/java/android/graphics/RenderEffect.java
@@ -290,6 +290,22 @@
         return new RenderEffect(nativeCreateShaderEffect(shader.getNativeInstance()));
     }
 
+    /**
+     * Create a {@link RenderEffect} that executes the provided {@link RuntimeShader} and passes
+     * the contents of the {@link android.graphics.RenderNode} that this RenderEffect is installed
+     * on as an input to the shader.
+     * @param shader the runtime shader that will bind the inputShaderName to the RenderEffect input
+     * @param uniformShaderName the uniform name defined in the RuntimeShader's program to which
+     *                         the contents of the RenderNode will be bound
+     */
+    @NonNull
+    public static RenderEffect createRuntimeShaderEffect(
+            @NonNull RuntimeShader shader, @NonNull String uniformShaderName) {
+        return new RenderEffect(
+                nativeCreateRuntimeShaderEffect(shader.getNativeShaderBuilder(),
+                        uniformShaderName));
+    }
+
     private final long mNativeRenderEffect;
 
     /* only constructed from static factory methods */
@@ -318,5 +334,7 @@
     private static native long nativeCreateBlendModeEffect(long dst, long src, int blendmode);
     private static native long nativeCreateChainEffect(long outer, long inner);
     private static native long nativeCreateShaderEffect(long shader);
+    private static native long nativeCreateRuntimeShaderEffect(
+            long shaderBuilder, String inputShaderName);
     private static native long nativeGetFinalizer();
 }
diff --git a/libs/WindowManager/Shell/Android.bp b/libs/WindowManager/Shell/Android.bp
index cdff585..e9b3c49 100644
--- a/libs/WindowManager/Shell/Android.bp
+++ b/libs/WindowManager/Shell/Android.bp
@@ -43,7 +43,7 @@
     name: "wm_shell_util-sources",
     srcs: [
         "src/com/android/wm/shell/util/**/*.java",
-        "src/com/android/wm/shell/common/split/SplitScreenConstants.java"
+        "src/com/android/wm/shell/common/split/SplitScreenConstants.java",
     ],
     path: "src",
 }
@@ -74,13 +74,13 @@
     ],
     tools: ["protologtool"],
     cmd: "$(location protologtool) transform-protolog-calls " +
-      "--protolog-class com.android.internal.protolog.common.ProtoLog " +
-      "--protolog-impl-class com.android.wm.shell.protolog.ShellProtoLogImpl " +
-      "--protolog-cache-class com.android.wm.shell.protolog.ShellProtoLogCache " +
-      "--loggroups-class com.android.wm.shell.protolog.ShellProtoLogGroup " +
-      "--loggroups-jar $(location :wm_shell_protolog-groups) " +
-      "--output-srcjar $(out) " +
-      "$(locations :wm_shell-sources)",
+        "--protolog-class com.android.internal.protolog.common.ProtoLog " +
+        "--protolog-impl-class com.android.wm.shell.protolog.ShellProtoLogImpl " +
+        "--protolog-cache-class com.android.wm.shell.protolog.ShellProtoLogCache " +
+        "--loggroups-class com.android.wm.shell.protolog.ShellProtoLogGroup " +
+        "--loggroups-jar $(location :wm_shell_protolog-groups) " +
+        "--output-srcjar $(out) " +
+        "$(locations :wm_shell-sources)",
     out: ["wm_shell_protolog.srcjar"],
 }
 
@@ -92,13 +92,14 @@
     ],
     tools: ["protologtool"],
     cmd: "$(location protologtool) generate-viewer-config " +
-      "--protolog-class com.android.internal.protolog.common.ProtoLog " +
-      "--loggroups-class com.android.wm.shell.protolog.ShellProtoLogGroup " +
-      "--loggroups-jar $(location :wm_shell_protolog-groups) " +
-      "--viewer-conf $(out) " +
-      "$(locations :wm_shell-sources)",
+        "--protolog-class com.android.internal.protolog.common.ProtoLog " +
+        "--loggroups-class com.android.wm.shell.protolog.ShellProtoLogGroup " +
+        "--loggroups-jar $(location :wm_shell_protolog-groups) " +
+        "--viewer-conf $(out) " +
+        "$(locations :wm_shell-sources)",
     out: ["wm_shell_protolog.json"],
 }
+
 // End ProtoLog
 
 java_library {
@@ -123,11 +124,12 @@
         "res",
     ],
     java_resources: [
-        ":generate-wm_shell_protolog.json"
+        ":generate-wm_shell_protolog.json",
     ],
     static_libs: [
         "androidx.appcompat_appcompat",
         "androidx.arch.core_core-runtime",
+        "androidx-constraintlayout_constraintlayout",
         "androidx.dynamicanimation_dynamicanimation",
         "androidx.recyclerview_recyclerview",
         "kotlinx-coroutines-android",
diff --git a/libs/WindowManager/Shell/res/layout/badged_image_view.xml b/libs/WindowManager/Shell/res/layout/badged_image_view.xml
new file mode 100644
index 0000000..5f07121
--- /dev/null
+++ b/libs/WindowManager/Shell/res/layout/badged_image_view.xml
@@ -0,0 +1,55 @@
+<?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"
+    xmlns:app="http://schemas.android.com/apk/res-auto">
+
+    <ImageView
+        android:id="@+id/icon_view"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:contentDescription="@null" />
+
+    <!--
+        Icon badge size is defined in Launcher3 BaseIconFactory as 0.444 of icon size.
+        Constraint guide starts from left, which means for a badge positioned on the right,
+        percent has to be 1 - 0.444 to have the same effect.
+    -->
+    <androidx.constraintlayout.widget.Guideline
+        android:id="@+id/app_icon_constraint_horizontal"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal"
+        app:layout_constraintGuide_percent="0.556" />
+
+    <androidx.constraintlayout.widget.Guideline
+        android:id="@+id/app_icon_constraint_vertical"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        app:layout_constraintGuide_percent="0.556" />
+
+    <ImageView
+        android:id="@+id/app_icon_view"
+        android:layout_width="0dp"
+        android:layout_height="0dp"
+        android:contentDescription="@null"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintLeft_toLeftOf="@id/app_icon_constraint_vertical"
+        app:layout_constraintRight_toRightOf="parent"
+        app:layout_constraintTop_toTopOf="@id/app_icon_constraint_horizontal" />
+
+</merge>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/values-af/strings.xml b/libs/WindowManager/Shell/res/values-af/strings.xml
index 107da81..8b32b38 100644
--- a/libs/WindowManager/Shell/res/values-af/strings.xml
+++ b/libs/WindowManager/Shell/res/values-af/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Bestuur"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Borrel is toegemaak."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"Tik om hierdie program te herbegin en maak volskerm oop."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-am/strings.xml b/libs/WindowManager/Shell/res/values-am/strings.xml
index d724372..8b898c0 100644
--- a/libs/WindowManager/Shell/res/values-am/strings.xml
+++ b/libs/WindowManager/Shell/res/values-am/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"ያቀናብሩ"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"አረፋ ተሰናብቷል።"</string>
     <string name="restart_button_description" msgid="5887656107651190519">"ይህን መተግበሪያ ዳግም ለማስነሳት መታ ያድርጉ እና ወደ ሙሉ ማያ ገጽ ይሂዱ።"</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-ar/strings.xml b/libs/WindowManager/Shell/res/values-ar/strings.xml
index 7dd1f81..a9eafdd 100644
--- a/libs/WindowManager/Shell/res/values-ar/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ar/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"إدارة"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"تم إغلاق الفقاعة."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"انقر لإعادة تشغيل هذا التطبيق والانتقال إلى وضع ملء الشاشة."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-as/strings.xml b/libs/WindowManager/Shell/res/values-as/strings.xml
index 190f7ca..a81d4e3 100644
--- a/libs/WindowManager/Shell/res/values-as/strings.xml
+++ b/libs/WindowManager/Shell/res/values-as/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"পৰিচালনা কৰক"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"বাবল অগ্ৰাহ্য কৰা হৈছে"</string>
     <string name="restart_button_description" msgid="5887656107651190519">"এপ্‌টো ৰিষ্টাৰ্ট কৰিবলৈ আৰু পূৰ্ণ স্ক্ৰীন ব্যৱহাৰ কৰিবলৈ টিপক।"</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-az/strings.xml b/libs/WindowManager/Shell/res/values-az/strings.xml
index e33a35f..45e3fdb 100644
--- a/libs/WindowManager/Shell/res/values-az/strings.xml
+++ b/libs/WindowManager/Shell/res/values-az/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"İdarə edin"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Qabarcıqdan imtina edilib."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"Bu tətbiqi sıfırlayaraq tam ekrana keçmək üçün toxunun."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
index f59e932..c17b3c4 100644
--- a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Upravljajte"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Oblačić je odbačen."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"Dodirnite da biste restartovali aplikaciju i prešli u režim celog ekrana."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-be/strings.xml b/libs/WindowManager/Shell/res/values-be/strings.xml
index 3b478f2..bcf7186 100644
--- a/libs/WindowManager/Shell/res/values-be/strings.xml
+++ b/libs/WindowManager/Shell/res/values-be/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Кіраваць"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Усплывальнае апавяшчэнне адхілена."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"Націсніце, каб перазапусціць гэту праграму і перайсці ў поўнаэкранны рэжым."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-bg/strings.xml b/libs/WindowManager/Shell/res/values-bg/strings.xml
index 3a77a1c..5f48744 100644
--- a/libs/WindowManager/Shell/res/values-bg/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bg/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Управление"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Балончето е отхвърлено."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"Докоснете, за да рестартирате това приложение в режим на цял екран."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-bn/strings.xml b/libs/WindowManager/Shell/res/values-bn/strings.xml
index 8bfd775..f96d65f 100644
--- a/libs/WindowManager/Shell/res/values-bn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bn/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"ম্যানেজ করুন"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"বাবল বাতিল করা হয়েছে।"</string>
     <string name="restart_button_description" msgid="5887656107651190519">"এই অ্যাপ রিস্টার্ট করতে ট্যাপ করুন ও \'ফুল-স্ক্রিন\' মোড ব্যবহার করুন।"</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-bs/strings.xml b/libs/WindowManager/Shell/res/values-bs/strings.xml
index d23cc61..1e068c6 100644
--- a/libs/WindowManager/Shell/res/values-bs/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bs/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Upravljaj"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Oblačić je odbačen."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"Dodirnite da ponovo pokrenete ovu aplikaciju i aktivirate prikaz preko cijelog ekrana."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-ca/strings.xml b/libs/WindowManager/Shell/res/values-ca/strings.xml
index 6434e31..97585ef 100644
--- a/libs/WindowManager/Shell/res/values-ca/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ca/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Gestiona"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"La bombolla s\'ha ignorat."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"Toca per reiniciar aquesta aplicació i passar a pantalla completa."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-cs/strings.xml b/libs/WindowManager/Shell/res/values-cs/strings.xml
index 3530a7c..7a3a890 100644
--- a/libs/WindowManager/Shell/res/values-cs/strings.xml
+++ b/libs/WindowManager/Shell/res/values-cs/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Spravovat"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bublina byla zavřena."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"Klepnutím aplikaci restartujete a přejdete na režim celé obrazovky"</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-da/strings.xml b/libs/WindowManager/Shell/res/values-da/strings.xml
index 89b66e5..4a025ba 100644
--- a/libs/WindowManager/Shell/res/values-da/strings.xml
+++ b/libs/WindowManager/Shell/res/values-da/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Administrer"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Boblen blev lukket."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"Tryk for at genstarte denne app, og gå til fuld skærm."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-de/strings.xml b/libs/WindowManager/Shell/res/values-de/strings.xml
index b49b446..bacd512 100644
--- a/libs/WindowManager/Shell/res/values-de/strings.xml
+++ b/libs/WindowManager/Shell/res/values-de/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Verwalten"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bubble verworfen."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"Tippe, um die App im Vollbildmodus neu zu starten."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-el/strings.xml b/libs/WindowManager/Shell/res/values-el/strings.xml
index ed1d913..f306ba3 100644
--- a/libs/WindowManager/Shell/res/values-el/strings.xml
+++ b/libs/WindowManager/Shell/res/values-el/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Διαχείριση"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Το συννεφάκι παραβλέφθηκε."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"Πατήστε για επανεκκίνηση αυτής της εφαρμογής και ενεργοποίηση πλήρους οθόνης."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
index 067e998..1ffbd039 100644
--- a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Manage"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bubble dismissed."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"Tap to restart this app and go full screen."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-en-rCA/strings.xml b/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
index 067e998..1ffbd039 100644
--- a/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Manage"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bubble dismissed."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"Tap to restart this app and go full screen."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
index 067e998..1ffbd039 100644
--- a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Manage"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bubble dismissed."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"Tap to restart this app and go full screen."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
index 067e998..1ffbd039 100644
--- a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Manage"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bubble dismissed."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"Tap to restart this app and go full screen."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-en-rXC/strings.xml b/libs/WindowManager/Shell/res/values-en-rXC/strings.xml
index 95c0d01..ffa3a65 100644
--- a/libs/WindowManager/Shell/res/values-en-rXC/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rXC/strings.xml
@@ -73,4 +73,7 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‏‎‏‎‎‏‎‎‎‏‎‏‏‎‎‎‏‏‏‎‏‎‎‎‎‏‎‎‎‏‏‎‎‏‎‎‎‏‎‎‏‏‎‎‎‏‎‏‎‎‏‏‏‎‎‏‏‎Manage‎‏‎‎‏‎"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‎‏‏‏‏‏‎‎‏‏‏‎‏‏‎‏‏‏‎‎‎‏‎‏‎‎‏‎‎‏‎‎‎‏‎‏‏‎‏‏‎‏‎‏‎‏‎‏‏‏‏‏‎‏‎Bubble dismissed.‎‏‎‎‏‎"</string>
     <string name="restart_button_description" msgid="5887656107651190519">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‎‏‏‎‏‏‎‏‎‏‎‎‏‎‏‎‎‎‎‎‎‎‏‎‎‏‎‎‏‎‏‎‎‎‎‎‏‏‎‏‎‏‎‏‎‎‏‏‏‎‏‏‏‏‎‏‏‏‎Tap to restart this app and go full screen.‎‏‎‎‏‎"</string>
+    <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‏‎‏‏‎‏‏‏‎‎‏‎‏‏‎‎‎‏‏‎‎‎‎‎‎‎‎‏‏‏‏‏‏‎‎‎‎‏‎‏‏‏‎‏‏‏‏‎‏‏‏‏‏‎Camera issues?‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎Tap to refit‎‏‎‎‏‎"</string>
+    <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‎‏‏‎‏‏‎‏‏‏‎‏‏‏‏‏‏‎‏‎‎‏‎‏‏‏‎‏‏‎‏‏‏‎‎‎‎‎‏‎‎‎‎‎‏‏‏‏‎‎‎‎‏‏‎‎‏‎Didn’t fix it?‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎Tap to revert‎‏‎‎‏‎"</string>
+    <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‎‏‏‎‎‏‎‏‏‎‎‏‎‎‎‎‏‎‎‏‎‎‏‎‎‎‏‎‎‏‏‎‎‏‏‎‎‎‎‎‏‏‎‎‎‏‏‏‏‎‎‏‎‎‏‏‏‎No camera issues? Tap to dismiss.‎‏‎‎‏‎"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
index 6e5347d..1ca7bfc 100644
--- a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
+++ b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Administrar"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Se descartó el cuadro."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"Presiona para reiniciar esta app y acceder al modo de pantalla completa."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-es/strings.xml b/libs/WindowManager/Shell/res/values-es/strings.xml
index 4820a0f..3d46421 100644
--- a/libs/WindowManager/Shell/res/values-es/strings.xml
+++ b/libs/WindowManager/Shell/res/values-es/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Gestionar"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Burbuja cerrada."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"Toca para reiniciar esta aplicación e ir a la pantalla completa."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-et/strings.xml b/libs/WindowManager/Shell/res/values-et/strings.xml
index 4c94694..4f5d563 100644
--- a/libs/WindowManager/Shell/res/values-et/strings.xml
+++ b/libs/WindowManager/Shell/res/values-et/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Halda"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Mullist loobuti."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"Puudutage rakenduse taaskäivitamiseks ja täisekraanrežiimi aktiveerimiseks."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-eu/strings.xml b/libs/WindowManager/Shell/res/values-eu/strings.xml
index afc4292..b76ccc8 100644
--- a/libs/WindowManager/Shell/res/values-eu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-eu/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Kudeatu"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Baztertu da globoa."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"Saka ezazu aplikazioa berrabiarazteko, eta ezarri pantaila osoko modua."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-fa/strings.xml b/libs/WindowManager/Shell/res/values-fa/strings.xml
index e8a0682..aef3c62 100644
--- a/libs/WindowManager/Shell/res/values-fa/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fa/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"مدیریت"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"حبابک رد شد."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"برای بازراه‌اندازی این برنامه و تغییر به حالت تمام‌صفحه، ضربه بزنید."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-fi/strings.xml b/libs/WindowManager/Shell/res/values-fi/strings.xml
index f671105..5f76ba4 100644
--- a/libs/WindowManager/Shell/res/values-fi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fi/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Ylläpidä"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Kupla ohitettu."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"Napauta, niin sovellus käynnistyy uudelleen ja siirtyy koko näytön tilaan."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
index 0d0b718..e1843e7 100644
--- a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Gérer"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bulle ignorée."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"Touchez pour redémarrer cette application et passer en plein écran."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-fr/strings.xml b/libs/WindowManager/Shell/res/values-fr/strings.xml
index 5652d7e..b3f3349 100644
--- a/libs/WindowManager/Shell/res/values-fr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fr/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Gérer"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bulle fermée."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"Appuyez pour redémarrer cette application et activer le mode plein écran."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-gl/strings.xml b/libs/WindowManager/Shell/res/values-gl/strings.xml
index 81bd916..3cdddf3 100644
--- a/libs/WindowManager/Shell/res/values-gl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-gl/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Xestionar"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Ignorouse a burbulla."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"Toca o botón para reiniciar esta aplicación e abrila en pantalla completa."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-gu/strings.xml b/libs/WindowManager/Shell/res/values-gu/strings.xml
index 3d408cf2..09d206e 100644
--- a/libs/WindowManager/Shell/res/values-gu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-gu/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"મેનેજ કરો"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"બબલ છોડી દેવાયો."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"આ ઍપ ફરીથી ચાલુ કરવા માટે ટૅપ કરીને પૂર્ણ સ્ક્રીન કરો."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-hi/strings.xml b/libs/WindowManager/Shell/res/values-hi/strings.xml
index 8c93e0a..0ce5114 100644
--- a/libs/WindowManager/Shell/res/values-hi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hi/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"मैनेज करें"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"बबल खारिज किया गया."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"इस ऐप्लिकेशन को रीस्टार्ट करने और फ़ुल स्क्रीन पर देखने के लिए टैप करें."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-hr/strings.xml b/libs/WindowManager/Shell/res/values-hr/strings.xml
index 1f8f982..e8c83f1 100644
--- a/libs/WindowManager/Shell/res/values-hr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hr/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Upravljanje"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Oblačić odbačen."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"Dodirnite da biste ponovo pokrenuli tu aplikaciju i prikazali je na cijelom zaslonu."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-hu/strings.xml b/libs/WindowManager/Shell/res/values-hu/strings.xml
index ebd02e5..6d60513 100644
--- a/libs/WindowManager/Shell/res/values-hu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hu/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Kezelés"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Buborék elvetve."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"Koppintson az alkalmazás újraindításához és a teljes képernyős mód elindításához."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-hy/strings.xml b/libs/WindowManager/Shell/res/values-hy/strings.xml
index 29b2052..f1ec076 100644
--- a/libs/WindowManager/Shell/res/values-hy/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hy/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Կառավարել"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Ամպիկը փակվեց։"</string>
     <string name="restart_button_description" msgid="5887656107651190519">"Հպեք՝ հավելվածը վերագործարկելու և լիաէկրան ռեժիմին անցնելու համար։"</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-in/strings.xml b/libs/WindowManager/Shell/res/values-in/strings.xml
index 6432aef..62dfcb7 100644
--- a/libs/WindowManager/Shell/res/values-in/strings.xml
+++ b/libs/WindowManager/Shell/res/values-in/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Kelola"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Balon ditutup."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"Ketuk untuk memulai ulang aplikasi ini dan membuka layar penuh."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-is/strings.xml b/libs/WindowManager/Shell/res/values-is/strings.xml
index 126d1f1..feab362 100644
--- a/libs/WindowManager/Shell/res/values-is/strings.xml
+++ b/libs/WindowManager/Shell/res/values-is/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Stjórna"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Blöðru lokað."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"Ýttu til að endurræsa forritið og sýna það á öllum skjánum."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-it/strings.xml b/libs/WindowManager/Shell/res/values-it/strings.xml
index ec221b1..bfcd385 100644
--- a/libs/WindowManager/Shell/res/values-it/strings.xml
+++ b/libs/WindowManager/Shell/res/values-it/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Gestisci"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Fumetto ignorato."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"Tocca per riavviare l\'app e passare alla modalità a schermo intero."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-iw/strings.xml b/libs/WindowManager/Shell/res/values-iw/strings.xml
index b87d10c..7ef5035 100644
--- a/libs/WindowManager/Shell/res/values-iw/strings.xml
+++ b/libs/WindowManager/Shell/res/values-iw/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"ניהול"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"הבועה נסגרה."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"צריך להקיש כדי להפעיל מחדש את האפליקציה הזו ולעבור למסך מלא."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-ja/strings.xml b/libs/WindowManager/Shell/res/values-ja/strings.xml
index 51ffca6..fb58abb 100644
--- a/libs/WindowManager/Shell/res/values-ja/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ja/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"管理"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"ふきだしが非表示になっています。"</string>
     <string name="restart_button_description" msgid="5887656107651190519">"タップしてこのアプリを再起動すると、全画面表示になります。"</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-ka/strings.xml b/libs/WindowManager/Shell/res/values-ka/strings.xml
index fc91d72..297d9af 100644
--- a/libs/WindowManager/Shell/res/values-ka/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ka/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"მართვა"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"ბუშტი დაიხურა."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"შეეხეთ ამ აპის გადასატვირთად და გადადით სრულ ეკრანზე."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-kk/strings.xml b/libs/WindowManager/Shell/res/values-kk/strings.xml
index 05a905d..7ca2f23 100644
--- a/libs/WindowManager/Shell/res/values-kk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-kk/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Басқару"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Қалқыма хабар жабылды."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"Бұл қолданбаны қайта қосып, толық экранға өту үшін түртіңіз."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-km/strings.xml b/libs/WindowManager/Shell/res/values-km/strings.xml
index 6a1cb2b..dae2293 100644
--- a/libs/WindowManager/Shell/res/values-km/strings.xml
+++ b/libs/WindowManager/Shell/res/values-km/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"គ្រប់គ្រង"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"បានច្រានចោល​សារលេចឡើង។"</string>
     <string name="restart_button_description" msgid="5887656107651190519">"ចុចដើម្បី​ចាប់ផ្ដើម​កម្មវិធី​នេះឡើងវិញ រួចចូលប្រើ​ពេញអេក្រង់។"</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-kn/strings.xml b/libs/WindowManager/Shell/res/values-kn/strings.xml
index aecb54b..72ba8ea 100644
--- a/libs/WindowManager/Shell/res/values-kn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-kn/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"ನಿರ್ವಹಿಸಿ"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"ಬಬಲ್ ವಜಾಗೊಳಿಸಲಾಗಿದೆ."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"ಈ ಆ್ಯಪ್ ಅನ್ನು ಮರುಪ್ರಾರಂಭಿಸಲು ಮತ್ತು ಪೂರ್ಣ ಸ್ಕ್ರೀನ್‌ನಲ್ಲಿ ನೋಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-ko/strings.xml b/libs/WindowManager/Shell/res/values-ko/strings.xml
index 5af9ca2a..d99abc4 100644
--- a/libs/WindowManager/Shell/res/values-ko/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ko/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"관리"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"대화창을 닫았습니다."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"탭하여 이 앱을 다시 시작하고 전체 화면으로 이동합니다."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-ky/strings.xml b/libs/WindowManager/Shell/res/values-ky/strings.xml
index 76f192e..fe25161 100644
--- a/libs/WindowManager/Shell/res/values-ky/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ky/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Башкаруу"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Калкып чыкма билдирме жабылды."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"Бул колдонмону өчүрүп күйгүзүп, толук экранга өтүү үчүн таптап коюңуз."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-lo/strings.xml b/libs/WindowManager/Shell/res/values-lo/strings.xml
index 4ec6313..786d837 100644
--- a/libs/WindowManager/Shell/res/values-lo/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lo/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"ຈັດການ"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"ປິດ Bubble ໄສ້ແລ້ວ."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"ແຕະເພື່ອຣີສະຕາດແອັບນີ້ ແລະ ໃຊ້ແບບເຕັມຈໍ."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-lt/strings.xml b/libs/WindowManager/Shell/res/values-lt/strings.xml
index 8630e91..32bdfc4 100644
--- a/libs/WindowManager/Shell/res/values-lt/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lt/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Tvarkyti"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Debesėlio atsisakyta."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"Palieskite, kad paleistumėte iš naujo šią programą ir įjungtumėte viso ekrano režimą."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-lv/strings.xml b/libs/WindowManager/Shell/res/values-lv/strings.xml
index b095b88..5d0f318 100644
--- a/libs/WindowManager/Shell/res/values-lv/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lv/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Pārvaldīt"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Burbulis ir noraidīts."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"Pieskarieties, lai restartētu šo lietotni un pārietu pilnekrāna režīmā."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-mk/strings.xml b/libs/WindowManager/Shell/res/values-mk/strings.xml
index 184fe9d..8c2e44c 100644
--- a/libs/WindowManager/Shell/res/values-mk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mk/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Управувајте"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Балончето е отфрлено."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"Допрете за да ја рестартирате апликацијава и да ја отворите на цел екран."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-ml/strings.xml b/libs/WindowManager/Shell/res/values-ml/strings.xml
index f1bfe9a..6c8883a 100644
--- a/libs/WindowManager/Shell/res/values-ml/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ml/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"മാനേജ് ചെയ്യുക"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"ബബിൾ ഡിസ്മിസ് ചെയ്തു."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"ഈ ആപ്പ് റീസ്‌റ്റാർട്ട് ചെയ്‌ത് പൂർണ്ണ സ്ക്രീനിലേക്ക് മാറാൻ ടാപ്പ് ചെയ്യുക."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-mn/strings.xml b/libs/WindowManager/Shell/res/values-mn/strings.xml
index 8b8cb95..d297923 100644
--- a/libs/WindowManager/Shell/res/values-mn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mn/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Удирдах"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Бөмбөлгийг үл хэрэгссэн."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"Энэ аппыг дахин эхлүүлж, бүтэн дэлгэцэд орохын тулд товшино уу."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-mr/strings.xml b/libs/WindowManager/Shell/res/values-mr/strings.xml
index c11af7b..3d9b53c 100644
--- a/libs/WindowManager/Shell/res/values-mr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mr/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"व्यवस्थापित करा"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"बबल डिसमिस केला."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"हे अ‍ॅप रीस्टार्ट करण्यासाठी आणि फुल स्क्रीन करण्यासाठी टॅप करा."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-ms/strings.xml b/libs/WindowManager/Shell/res/values-ms/strings.xml
index 5493ce5..0aafb59 100644
--- a/libs/WindowManager/Shell/res/values-ms/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ms/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Urus"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Gelembung diketepikan."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"Ketik untuk memulakan semula apl ini dan menggunakan skrin penuh."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-my/strings.xml b/libs/WindowManager/Shell/res/values-my/strings.xml
index e1d17f8..899c607 100644
--- a/libs/WindowManager/Shell/res/values-my/strings.xml
+++ b/libs/WindowManager/Shell/res/values-my/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"စီမံရန်"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"ပူဖောင်းကွက် ဖယ်လိုက်သည်။"</string>
     <string name="restart_button_description" msgid="5887656107651190519">"ဤအက်ပ်ကို ပြန်စပြီး ဖန်သားပြင်အပြည့်လုပ်ရန် တို့ပါ။"</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-nb/strings.xml b/libs/WindowManager/Shell/res/values-nb/strings.xml
index 87bc7da..60891d3 100644
--- a/libs/WindowManager/Shell/res/values-nb/strings.xml
+++ b/libs/WindowManager/Shell/res/values-nb/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Administrer"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Boblen er avvist."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"Trykk for å starte denne appen på nytt og vise den i fullskjerm."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-ne/strings.xml b/libs/WindowManager/Shell/res/values-ne/strings.xml
index 12df158..8bd6907 100644
--- a/libs/WindowManager/Shell/res/values-ne/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ne/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"व्यवस्थापन गर्नुहोस्"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"बबल हटाइयो।"</string>
     <string name="restart_button_description" msgid="5887656107651190519">"यो एप रिस्टार्ट गर्न ट्याप गर्नुहोस् र फुल स्क्रिन मोडमा जानुहोस्।"</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-nl/strings.xml b/libs/WindowManager/Shell/res/values-nl/strings.xml
index f83ad22..3fddf34 100644
--- a/libs/WindowManager/Shell/res/values-nl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-nl/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Beheren"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bubbel gesloten."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"Tik om deze app opnieuw te starten en te openen op het volledige scherm."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-or/strings.xml b/libs/WindowManager/Shell/res/values-or/strings.xml
index 14f92c8..217556e 100644
--- a/libs/WindowManager/Shell/res/values-or/strings.xml
+++ b/libs/WindowManager/Shell/res/values-or/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"ପରିଚାଳନା କରନ୍ତୁ"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"ବବଲ୍ ଖାରଜ କରାଯାଇଛି।"</string>
     <string name="restart_button_description" msgid="5887656107651190519">"ଏହି ଆପକୁ ରିଷ୍ଟାର୍ଟ କରି ପୂର୍ଣ୍ଣ ସ୍କ୍ରିନ୍ କରିବାକୁ ଟାପ୍ କରନ୍ତୁ।"</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-pa/strings.xml b/libs/WindowManager/Shell/res/values-pa/strings.xml
index e09f53adb..dc4dae1 100644
--- a/libs/WindowManager/Shell/res/values-pa/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pa/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"ਪ੍ਰਬੰਧਨ ਕਰੋ"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"ਬਬਲ ਨੂੰ ਖਾਰਜ ਕੀਤਾ ਗਿਆ।"</string>
     <string name="restart_button_description" msgid="5887656107651190519">"ਇਸ ਐਪ ਨੂੰ ਮੁੜ-ਸ਼ੁਰੂ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ ਅਤੇ ਪੂਰੀ ਸਕ੍ਰੀਨ ਮੋਡ \'ਤੇ ਜਾਓ।"</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-pl/strings.xml b/libs/WindowManager/Shell/res/values-pl/strings.xml
index a2ef997..fccd138 100644
--- a/libs/WindowManager/Shell/res/values-pl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pl/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Zarządzaj"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Zamknięto dymek"</string>
     <string name="restart_button_description" msgid="5887656107651190519">"Kliknij, by uruchomić tę aplikację ponownie i przejść w tryb pełnoekranowy."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml b/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
index 1300e53..5664030 100644
--- a/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Gerenciar"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Balão dispensado."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"Toque para reiniciar o app e usar tela cheia."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
index f3314f8..abe6a01 100644
--- a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Gerir"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Balão ignorado."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"Toque para reiniciar esta app e ficar em ecrã inteiro."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-pt/strings.xml b/libs/WindowManager/Shell/res/values-pt/strings.xml
index 1300e53..5664030 100644
--- a/libs/WindowManager/Shell/res/values-pt/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Gerenciar"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Balão dispensado."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"Toque para reiniciar o app e usar tela cheia."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-ro/strings.xml b/libs/WindowManager/Shell/res/values-ro/strings.xml
index 01f96c8..39dec90 100644
--- a/libs/WindowManager/Shell/res/values-ro/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ro/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Gestionați"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Balonul a fost respins."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"Atingeți ca să reporniți aplicația și să treceți în modul ecran complet."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-ru/strings.xml b/libs/WindowManager/Shell/res/values-ru/strings.xml
index 6a0e9c1..e3c2215 100644
--- a/libs/WindowManager/Shell/res/values-ru/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ru/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Настроить"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Всплывающий чат закрыт."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"Нажмите, чтобы перезапустить приложение и перейти в полноэкранный режим."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-si/strings.xml b/libs/WindowManager/Shell/res/values-si/strings.xml
index d7ed246..efaf1f3 100644
--- a/libs/WindowManager/Shell/res/values-si/strings.xml
+++ b/libs/WindowManager/Shell/res/values-si/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"කළමනා කරන්න"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"බුබුල ඉවත දමා ඇත."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"මෙම යෙදුම යළි ඇරඹීමට සහ පූර්ණ තිරයට යාමට තට්ටු කරන්න."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-sk/strings.xml b/libs/WindowManager/Shell/res/values-sk/strings.xml
index 13fd58f..a827153 100644
--- a/libs/WindowManager/Shell/res/values-sk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sk/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Spravovať"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bublina bola zavretá."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"Klepnutím reštartujete túto aplikáciu a prejdete do režimu celej obrazovky."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-sl/strings.xml b/libs/WindowManager/Shell/res/values-sl/strings.xml
index 6a68069..7437654 100644
--- a/libs/WindowManager/Shell/res/values-sl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sl/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Upravljanje"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Oblaček je bil opuščen."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"Dotaknite se za vnovični zagon te aplikacije in preklop v celozaslonski način."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-sq/strings.xml b/libs/WindowManager/Shell/res/values-sq/strings.xml
index 7382a48..bda10c8 100644
--- a/libs/WindowManager/Shell/res/values-sq/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sq/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Menaxho"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Flluska u hoq."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"Trokit për ta rinisur këtë aplikacion dhe për të kaluar në ekranin e plotë."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-sr/strings.xml b/libs/WindowManager/Shell/res/values-sr/strings.xml
index c0c1e3f..98e13be 100644
--- a/libs/WindowManager/Shell/res/values-sr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sr/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Управљајте"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Облачић је одбачен."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"Додирните да бисте рестартовали апликацију и прешли у режим целог екрана."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-sv/strings.xml b/libs/WindowManager/Shell/res/values-sv/strings.xml
index 34254d9..3080088 100644
--- a/libs/WindowManager/Shell/res/values-sv/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sv/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Hantera"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bubblan ignorerades."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"Tryck för att starta om appen i helskärmsläge."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-sw/strings.xml b/libs/WindowManager/Shell/res/values-sw/strings.xml
index 82a9f14..9fb7460 100644
--- a/libs/WindowManager/Shell/res/values-sw/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sw/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Dhibiti"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Umeondoa kiputo."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"Gusa ili uzime na uwashe programu hii, kisha nenda kwenye skrini nzima."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-ta/strings.xml b/libs/WindowManager/Shell/res/values-ta/strings.xml
index 0ed778a..d7f17aa 100644
--- a/libs/WindowManager/Shell/res/values-ta/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ta/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"நிர்வகி"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"குமிழ் நிராகரிக்கப்பட்டது."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"தட்டுவதன் மூலம் இந்த ஆப்ஸை மீண்டும் தொடங்கலாம், முழுத்திரையில் பார்க்கலாம்."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-te/strings.xml b/libs/WindowManager/Shell/res/values-te/strings.xml
index 8fef67b..4e421b5 100644
--- a/libs/WindowManager/Shell/res/values-te/strings.xml
+++ b/libs/WindowManager/Shell/res/values-te/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"మేనేజ్ చేయండి"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"బబుల్ విస్మరించబడింది."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"ఈ యాప్‌ను రీస్టార్ట్ చేయడానికి ట్యాప్ చేసి, ఆపై పూర్తి స్క్రీన్‌లోకి వెళ్లండి."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-th/strings.xml b/libs/WindowManager/Shell/res/values-th/strings.xml
index 06b04f1..52f94e6 100644
--- a/libs/WindowManager/Shell/res/values-th/strings.xml
+++ b/libs/WindowManager/Shell/res/values-th/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"จัดการ"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"ปิดบับเบิลแล้ว"</string>
     <string name="restart_button_description" msgid="5887656107651190519">"แตะเพื่อรีสตาร์ทแอปนี้และแสดงแบบเต็มหน้าจอ"</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-tl/strings.xml b/libs/WindowManager/Shell/res/values-tl/strings.xml
index 62642c1..d7b671d 100644
--- a/libs/WindowManager/Shell/res/values-tl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-tl/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Pamahalaan"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Na-dismiss na ang bubble."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"I-tap para i-restart ang app na ito at mag-full screen."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-tr/strings.xml b/libs/WindowManager/Shell/res/values-tr/strings.xml
index 971520a..c618f6c 100644
--- a/libs/WindowManager/Shell/res/values-tr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-tr/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Yönet"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Balon kapatıldı."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"Bu uygulamayı yeniden başlatmak ve tam ekrana geçmek için dokunun."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-uk/strings.xml b/libs/WindowManager/Shell/res/values-uk/strings.xml
index 3014735..ec2e550 100644
--- a/libs/WindowManager/Shell/res/values-uk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-uk/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Налаштувати"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Спливаюче сповіщення закрито."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"Натисніть, щоб перезапустити додаток і перейти в повноекранний режим."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-ur/strings.xml b/libs/WindowManager/Shell/res/values-ur/strings.xml
index 07319ef..18e1e51 100644
--- a/libs/WindowManager/Shell/res/values-ur/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ur/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"نظم کریں"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"بلبلہ برخاست کر دیا گیا۔"</string>
     <string name="restart_button_description" msgid="5887656107651190519">"یہ ایپ دوبارہ شروع کرنے کے لیے تھپتھپائیں اور پوری اسکرین پر جائیں۔"</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-uz/strings.xml b/libs/WindowManager/Shell/res/values-uz/strings.xml
index 4c79d64..f6c7ed2 100644
--- a/libs/WindowManager/Shell/res/values-uz/strings.xml
+++ b/libs/WindowManager/Shell/res/values-uz/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Boshqarish"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bulutcha yopildi."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"Bu ilovani qaytadan ishga tushirish va butun ekranda ochish uchun bosing."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-vi/strings.xml b/libs/WindowManager/Shell/res/values-vi/strings.xml
index b9f23cd..1cab8e7 100644
--- a/libs/WindowManager/Shell/res/values-vi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-vi/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Quản lý"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Đã đóng bong bóng."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"Nhấn để khởi động lại ứng dụng này và xem ở chế độ toàn màn hình."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
index c007258..dc12c4f 100644
--- a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"管理"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"已关闭对话泡。"</string>
     <string name="restart_button_description" msgid="5887656107651190519">"点按即可重启此应用并进入全屏模式。"</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
index 5e33677..fe114ac 100644
--- a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"管理"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"對話氣泡已關閉。"</string>
     <string name="restart_button_description" msgid="5887656107651190519">"輕按即可重新開啟此應用程式並放大至全螢幕。"</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
index 2439a97..0e4fc30 100644
--- a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"管理"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"已關閉泡泡。"</string>
     <string name="restart_button_description" msgid="5887656107651190519">"輕觸即可重新啟動這個應用程式並進入全螢幕模式。"</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-zu/strings.xml b/libs/WindowManager/Shell/res/values-zu/strings.xml
index 20128f6..f563f1f 100644
--- a/libs/WindowManager/Shell/res/values-zu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zu/strings.xml
@@ -73,4 +73,10 @@
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Phatha"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Ibhamuza licashisiwe."</string>
     <string name="restart_button_description" msgid="5887656107651190519">"Thepha ukuze uqale kabusha lolu hlelo lokusebenza uphinde uye kusikrini esigcwele."</string>
+    <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+    <skip />
+    <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+    <skip />
+    <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+    <skip />
 </resources>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java
index 686fbbf..c52d87d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java
@@ -19,7 +19,6 @@
 import android.annotation.Nullable;
 import android.content.Context;
 import android.content.res.TypedArray;
-import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Outline;
 import android.graphics.Path;
@@ -27,14 +26,16 @@
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.util.PathParser;
-import android.view.Gravity;
+import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewOutlineProvider;
-import android.widget.FrameLayout;
 import android.widget.ImageView;
 
+import androidx.constraintlayout.widget.ConstraintLayout;
+
 import com.android.launcher3.icons.DotRenderer;
 import com.android.launcher3.icons.IconNormalizer;
+import com.android.wm.shell.R;
 import com.android.wm.shell.animation.Interpolators;
 
 import java.util.EnumSet;
@@ -46,14 +47,12 @@
  * Badge = the icon associated with the app that created this bubble, this will show work profile
  * badge if appropriate.
  */
-public class BadgedImageView extends FrameLayout {
+public class BadgedImageView extends ConstraintLayout {
 
     /** Same value as Launcher3 dot code */
     public static final float WHITE_SCRIM_ALPHA = 0.54f;
     /** Same as value in Launcher3 IconShape */
     public static final int DEFAULT_PATH_SIZE = 100;
-    /** Same as value in Launcher3 BaseIconFactory */
-    private static final float ICON_BADGE_SCALE = 0.444f;
 
     /**
      * Flags that suppress the visibility of the 'new' dot, for one reason or another. If any of
@@ -105,11 +104,13 @@
     public BadgedImageView(Context context, AttributeSet attrs, int defStyleAttr,
             int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
+        // We manage positioning the badge ourselves
+        setLayoutDirection(LAYOUT_DIRECTION_LTR);
 
-        mBubbleIcon = new ImageView(context);
-        addView(mBubbleIcon);
-        mAppIcon = new ImageView(context);
-        addView(mAppIcon);
+        LayoutInflater.from(context).inflate(R.layout.badged_image_view, this);
+
+        mBubbleIcon = findViewById(R.id.icon_view);
+        mAppIcon = findViewById(R.id.app_icon_view);
 
         final TypedArray ta = mContext.obtainStyledAttributes(attrs, new int[]{android.R.attr.src},
                 defStyleAttr, defStyleRes);
@@ -161,6 +162,7 @@
     public void setRenderedBubble(BubbleViewProvider bubble) {
         mBubble = bubble;
         mBubbleIcon.setImageBitmap(bubble.getBubbleIcon());
+        mAppIcon.setImageBitmap(bubble.getAppBadge());
         if (mDotSuppressionFlags.contains(SuppressionFlag.BEHIND_STACK)) {
             hideBadge();
         } else {
@@ -348,26 +350,17 @@
     }
 
     void showBadge() {
-        Bitmap badge = mBubble.getAppBadge();
-        if (badge == null) {
+        if (mBubble.getAppBadge() == null) {
             mAppIcon.setVisibility(GONE);
             return;
         }
-
-        final int bubbleSize = mBubble.getBubbleIcon().getWidth();
-        final int badgeSize = (int) (ICON_BADGE_SCALE * bubbleSize);
-
-        FrameLayout.LayoutParams appIconParams = (LayoutParams) mAppIcon.getLayoutParams();
-        appIconParams.height = badgeSize;
-        appIconParams.width = badgeSize;
+        int translationX;
         if (mOnLeft) {
-            appIconParams.gravity = Gravity.BOTTOM | Gravity.LEFT;
+            translationX = -(mBubbleIcon.getWidth() - mAppIcon.getWidth());
         } else {
-            appIconParams.gravity = Gravity.BOTTOM | Gravity.RIGHT;
+            translationX = 0;
         }
-        mAppIcon.setLayoutParams(appIconParams);
-
-        mAppIcon.setImageBitmap(badge);
+        mAppIcon.setTranslationX(translationX);
         mAppIcon.setVisibility(VISIBLE);
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
index 8d43f13..eaeade8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
@@ -108,6 +108,8 @@
     private Bitmap mBubbleBitmap;
     // The app badge for the bubble
     private Bitmap mBadgeBitmap;
+    // App badge without any markings for important conversations
+    private Bitmap mRawBadgeBitmap;
     private int mDotColor;
     private Path mDotPath;
     private int mFlags;
@@ -248,6 +250,11 @@
     }
 
     @Override
+    public Bitmap getRawAppBadge() {
+        return mRawBadgeBitmap;
+    }
+
+    @Override
     public int getDotColor() {
         return mDotColor;
     }
@@ -409,6 +416,7 @@
         mFlyoutMessage = info.flyoutMessage;
 
         mBadgeBitmap = info.badgeBitmap;
+        mRawBadgeBitmap = info.mRawBadgeBitmap;
         mBubbleBitmap = info.bubbleBitmap;
 
         mDotColor = info.dotColor;
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 af59062..9ae67a9 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
@@ -386,13 +386,14 @@
         final TypedArray ta = mContext.obtainStyledAttributes(new int[] {
                 android.R.attr.dialogCornerRadius,
                 android.R.attr.colorBackgroundFloating});
-        mCornerRadius = ta.getDimensionPixelSize(0, 0);
+        boolean supportsRoundedCorners = ScreenDecorationsUtils.supportsRoundedCornersOnWindows(
+                mContext.getResources());
+        mCornerRadius = supportsRoundedCorners ? ta.getDimensionPixelSize(0, 0) : 0;
         mBackgroundColorFloating = ta.getColor(1, Color.WHITE);
         mExpandedViewContainer.setBackgroundColor(mBackgroundColorFloating);
         ta.recycle();
 
-        if (mTaskView != null && ScreenDecorationsUtils.supportsRoundedCornersOnWindows(
-                mContext.getResources())) {
+        if (mTaskView != null) {
             mTaskView.setCornerRadius(mCornerRadius);
         }
         updatePointerView();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt
index a175929..dd751d2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt
@@ -141,6 +141,10 @@
         return null
     }
 
+    override fun getRawAppBadge(): Bitmap? {
+        return null
+    }
+
     override fun getBubbleIcon(): Bitmap {
         return bitmap
     }
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 b40021e..df3780e 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
@@ -70,6 +70,7 @@
 import androidx.dynamicanimation.animation.SpringForce;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.policy.ScreenDecorationsUtils;
 import com.android.internal.util.FrameworkStatsLog;
 import com.android.wm.shell.R;
 import com.android.wm.shell.animation.Interpolators;
@@ -822,7 +823,9 @@
         mAnimatingOutSurfaceView = new SurfaceView(getContext());
         mAnimatingOutSurfaceView.setUseAlpha();
         mAnimatingOutSurfaceView.setZOrderOnTop(true);
-        mAnimatingOutSurfaceView.setCornerRadius(mCornerRadius);
+        boolean supportsRoundedCorners = ScreenDecorationsUtils.supportsRoundedCornersOnWindows(
+                mContext.getResources());
+        mAnimatingOutSurfaceView.setCornerRadius(supportsRoundedCorners ? mCornerRadius : 0);
         mAnimatingOutSurfaceView.setLayoutParams(new ViewGroup.LayoutParams(0, 0));
         mAnimatingOutSurfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
             @Override
@@ -2612,11 +2615,13 @@
 
         // If available, update the manage menu's settings option with the expanded bubble's app
         // name and icon.
-        if (show && mBubbleData.hasBubbleInStackWithKey(mExpandedBubble.getKey())) {
+        if (show) {
             final Bubble bubble = mBubbleData.getBubbleInStackWithKey(mExpandedBubble.getKey());
-            mManageSettingsIcon.setImageBitmap(bubble.getAppBadge());
-            mManageSettingsText.setText(getResources().getString(
-                    R.string.bubbles_app_settings, bubble.getAppName()));
+            if (bubble != null) {
+                mManageSettingsIcon.setImageBitmap(bubble.getRawAppBadge());
+                mManageSettingsText.setText(getResources().getString(
+                        R.string.bubbles_app_settings, bubble.getAppName()));
+            }
         }
 
         if (mExpandedBubble.getExpandedView().getTaskView() != null) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java
index 91aff3e..b01c756 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java
@@ -127,6 +127,7 @@
         String appName;
         Bitmap bubbleBitmap;
         Bitmap badgeBitmap;
+        Bitmap mRawBadgeBitmap;
         int dotColor;
         Path dotPath;
         Bubble.FlyoutMessage flyoutMessage;
@@ -189,6 +190,8 @@
             BitmapInfo badgeBitmapInfo = iconFactory.getBadgeBitmap(badgedIcon,
                     b.isImportantConversation());
             info.badgeBitmap = badgeBitmapInfo.icon;
+            // Raw badge bitmap never includes the important conversation ring
+            info.mRawBadgeBitmap = iconFactory.getBadgeBitmap(badgedIcon, false).icon;
             info.bubbleBitmap = iconFactory.createBadgedIconBitmap(bubbleDrawable).icon;
 
             // Dot color & placement
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewProvider.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewProvider.java
index 7e55282..3f6d41b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewProvider.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewProvider.java
@@ -43,6 +43,9 @@
     /** App badge drawable to draw above bubble icon. */
     @Nullable Bitmap getAppBadge();
 
+    /** Base app badge drawable without any markings. */
+    @Nullable Bitmap getRawAppBadge();
+
     /** Path of normalized bubble icon to draw dot on. */
     Path getDotPath();
 
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 a9e0c48..f7c92fe 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
@@ -123,7 +123,7 @@
         mDividerWindowWidth = mDividerSize + 2 * mDividerInsets;
 
         mRootBounds.set(configuration.windowConfiguration.getBounds());
-        mDividerSnapAlgorithm = getSnapAlgorithm(mContext, mRootBounds);
+        mDividerSnapAlgorithm = getSnapAlgorithm(mContext, mRootBounds, null);
         resetDividerPosition();
     }
 
@@ -201,7 +201,7 @@
         mTempRect.set(mRootBounds);
         mRootBounds.set(rootBounds);
         mRotation = rotation;
-        mDividerSnapAlgorithm = getSnapAlgorithm(mContext, mRootBounds);
+        mDividerSnapAlgorithm = getSnapAlgorithm(mContext, mRootBounds, null);
         initDividerPosition(mTempRect);
 
         if (mInitialized) {
@@ -212,8 +212,9 @@
         return true;
     }
 
-    /** Rotate the layout to specific rotation and assume its new bounds. */
-    public void rotateTo(int newRotation) {
+    /** Rotate the layout to specific rotation and calculate new bounds. The stable insets value
+     *  should be calculated by display layout. */
+    public void rotateTo(int newRotation, Rect stableInsets) {
         final int rotationDelta = (newRotation - mRotation + 4) % 4;
         final boolean changeOrient = (rotationDelta % 2) != 0;
 
@@ -223,11 +224,11 @@
             tmpRect.set(mRootBounds.top, mRootBounds.left, mRootBounds.bottom, mRootBounds.right);
         }
 
-        final Configuration config = new Configuration();
-        config.setTo(mContext.getResources().getConfiguration());
-        config.orientation = mOrientation;
-        config.windowConfiguration.setBounds(tmpRect);
-        updateConfiguration(config);
+        // We only need new bounds here, other configuration should be update later.
+        mTempRect.set(mRootBounds);
+        mRootBounds.set(tmpRect);
+        mDividerSnapAlgorithm = getSnapAlgorithm(mContext, mRootBounds, stableInsets);
+        initDividerPosition(mTempRect);
     }
 
     private void initDividerPosition(Rect oldBounds) {
@@ -372,7 +373,8 @@
         return mDividerSnapAlgorithm.calculateSnapTarget(position, velocity, hardDismiss);
     }
 
-    private DividerSnapAlgorithm getSnapAlgorithm(Context context, Rect rootBounds) {
+    private DividerSnapAlgorithm getSnapAlgorithm(Context context, Rect rootBounds,
+            @Nullable Rect stableInsets) {
         final boolean isLandscape = isLandscape(rootBounds);
         return new DividerSnapAlgorithm(
                 context.getResources(),
@@ -380,7 +382,7 @@
                 rootBounds.height(),
                 mDividerSize,
                 !isLandscape,
-                getDisplayInsets(context),
+                stableInsets != null ? stableInsets : getDisplayInsets(context),
                 isLandscape ? DOCKED_LEFT : DOCKED_TOP /* dockSide */);
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
index d70857a4..4f01dc6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
@@ -309,10 +309,11 @@
             PipAnimationController pipAnimationController, PipBoundsAlgorithm pipBoundsAlgorithm,
             PipBoundsState pipBoundsState, PipTransitionState pipTransitionState,
             PhonePipMenuController pipMenuController,
-            PipSurfaceTransactionHelper pipSurfaceTransactionHelper) {
+            PipSurfaceTransactionHelper pipSurfaceTransactionHelper,
+            Optional<SplitScreenController> splitScreenOptional) {
         return new PipTransition(context, pipBoundsState, pipTransitionState, pipMenuController,
                 pipBoundsAlgorithm, pipAnimationController, transitions, shellTaskOrganizer,
-                pipSurfaceTransactionHelper);
+                pipSurfaceTransactionHelper, splitScreenOptional);
     }
 
     @WMSingleton
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 507204c..c9c73fd 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
@@ -277,6 +277,7 @@
         registerSettingObservers(mUserId);
         setupTimeoutListener();
         updateSettings();
+        updateDisplayLayout(mContext.getDisplayId());
 
         mAccessibilityManager = AccessibilityManager.getInstance(context);
         mAccessibilityManager.addAccessibilityStateChangeListener(
@@ -448,8 +449,13 @@
         onShortcutEnabledChanged();
     }
 
-    private void updateDisplayLayout(int displayId) {
+    @VisibleForTesting
+    void updateDisplayLayout(int displayId) {
         final DisplayLayout newDisplayLayout = mDisplayController.getDisplayLayout(displayId);
+        if (newDisplayLayout == null) {
+            Slog.w(TAG, "Failed to get new DisplayLayout.");
+            return;
+        }
         mDisplayAreaOrganizer.setDisplayLayout(newDisplayLayout);
         mTutorialHandler.onDisplayChanged(newDisplayLayout);
         mBackgroundPanelOrganizer.onDisplayChanged(newDisplayLayout);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java
index 1b2f476..ec3ef5a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java
@@ -123,9 +123,8 @@
             OneHandedBackgroundPanelOrganizer oneHandedBackgroundGradientOrganizer,
             ShellExecutor mainExecutor) {
         super(mainExecutor);
-        mDisplayLayout.set(displayLayout);
+        setDisplayLayout(displayLayout);
         mOneHandedSettingsUtil = oneHandedSettingsUtil;
-        updateDisplayBounds();
         mAnimationController = animationController;
         final int animationDurationConfig = context.getResources().getInteger(
                 R.integer.config_one_handed_translate_animation_duration);
@@ -282,6 +281,7 @@
     @VisibleForTesting
     void setDisplayLayout(@NonNull DisplayLayout displayLayout) {
         mDisplayLayout.set(displayLayout);
+        updateDisplayBounds();
     }
 
     @VisibleForTesting
@@ -289,6 +289,7 @@
         return mDisplayAreaTokenMap;
     }
 
+    @VisibleForTesting
     void updateDisplayBounds() {
         mDefaultDisplayBounds.set(0, 0, mDisplayLayout.width(), mDisplayLayout.height());
         mLastVisualDisplayBounds.set(mDefaultDisplayBounds);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
index 9575b0a..e616172 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
@@ -584,9 +584,11 @@
                     setCurrentValue(bounds);
                     if (inScaleTransition() || sourceHintRect == null) {
                         if (isOutPipDirection) {
-                            getSurfaceTransactionHelper().scale(tx, leash, end, bounds);
+                            getSurfaceTransactionHelper().crop(tx, leash, end)
+                                    .scale(tx, leash, end, bounds);
                         } else {
-                            getSurfaceTransactionHelper().scale(tx, leash, base, bounds, angle)
+                            getSurfaceTransactionHelper().crop(tx, leash, base)
+                                    .scale(tx, leash, base, bounds, angle)
                                     .round(tx, leash, base, bounds);
                         }
                     } else {
@@ -622,13 +624,13 @@
                         if (rotationDelta == ROTATION_90) {
                             degree = 90 * (1 - fraction);
                             x = fraction * (end.left - start.left)
-                                    + start.left + start.right * (1 - fraction);
+                                    + start.left + start.width() * (1 - fraction);
                             y = fraction * (end.top - start.top) + start.top;
                         } else {
                             degree = -90 * (1 - fraction);
                             x = fraction * (end.left - start.left) + start.left;
                             y = fraction * (end.top - start.top)
-                                    + start.top + start.bottom * (1 - fraction);
+                                    + start.top + start.height() * (1 - fraction);
                         }
                     } else {
                         if (rotationDelta == ROTATION_90) {
@@ -646,8 +648,10 @@
                     getSurfaceTransactionHelper()
                             .rotateAndScaleWithCrop(tx, leash, initialContainerRect, bounds,
                                     insets, degree, x, y, isOutPipDirection,
-                                    rotationDelta == ROTATION_270 /* clockwise */)
-                            .round(tx, leash, sourceBounds, bounds);
+                                    rotationDelta == ROTATION_270 /* clockwise */);
+                    if (shouldApplyCornerRadius()) {
+                        getSurfaceTransactionHelper().round(tx, leash, sourceBounds, bounds);
+                    }
                     tx.apply();
                 }
 
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 f0b2716..4c09a4e 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
@@ -25,6 +25,8 @@
 
 import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_PIP;
 import static com.android.wm.shell.ShellTaskOrganizer.taskListenerTypeToString;
+import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
+import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
 import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_ALPHA;
 import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_BOUNDS;
 import static com.android.wm.shell.pip.PipAnimationController.FRACTION_START;
@@ -40,6 +42,10 @@
 import static com.android.wm.shell.pip.PipAnimationController.isInPipDirection;
 import static com.android.wm.shell.pip.PipAnimationController.isOutPipDirection;
 import static com.android.wm.shell.pip.PipAnimationController.isRemovePipDirection;
+import static com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS;
+import static com.android.wm.shell.transition.Transitions.TRANSIT_EXIT_PIP;
+import static com.android.wm.shell.transition.Transitions.TRANSIT_EXIT_PIP_TO_SPLIT;
+import static com.android.wm.shell.transition.Transitions.TRANSIT_REMOVE_PIP;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -394,27 +400,54 @@
         mPipUiEventLoggerLogger.log(
                 PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_EXPAND_TO_FULLSCREEN);
         final WindowContainerTransaction wct = new WindowContainerTransaction();
+
+        if (ENABLE_SHELL_TRANSITIONS) {
+            if (requestEnterSplit && mSplitScreenOptional.isPresent()) {
+                mSplitScreenOptional.get().prepareEnterSplitScreen(wct, mTaskInfo,
+                        isPipTopLeft()
+                                ? SPLIT_POSITION_TOP_OR_LEFT : SPLIT_POSITION_BOTTOM_OR_RIGHT);
+                mPipTransitionController.startExitTransition(
+                        TRANSIT_EXIT_PIP_TO_SPLIT, wct, null /* destinationBounds */);
+                return;
+            }
+        }
+
         final Rect destinationBounds = mPipBoundsState.getDisplayBounds();
         final int direction = syncWithSplitScreenBounds(destinationBounds, requestEnterSplit)
                 ? TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN
                 : TRANSITION_DIRECTION_LEAVE_PIP;
-        final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction();
-        mSurfaceTransactionHelper.scale(tx, mLeash, destinationBounds, mPipBoundsState.getBounds());
-        tx.setWindowCrop(mLeash, destinationBounds.width(), destinationBounds.height());
-        // We set to fullscreen here for now, but later it will be set to UNDEFINED for
-        // the proper windowing mode to take place. See #applyWindowingModeChangeOnExit.
-        wct.setActivityWindowingMode(mToken,
-                direction == TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN && !requestEnterSplit
-                        ? WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
-                        : WINDOWING_MODE_FULLSCREEN);
-        wct.setBounds(mToken, destinationBounds);
-        wct.setBoundsChangeTransaction(mToken, tx);
+
+        if (Transitions.ENABLE_SHELL_TRANSITIONS && direction == TRANSITION_DIRECTION_LEAVE_PIP) {
+            // When exit to fullscreen with Shell transition enabled, we update the Task windowing
+            // mode directly so that it can also trigger display rotation and visibility update in
+            // the same transition if there will be any.
+            wct.setWindowingMode(mToken, WINDOWING_MODE_UNDEFINED);
+            // We can inherit the parent bounds as it is going to be fullscreen. The
+            // destinationBounds calculated above will be incorrect if this is with rotation.
+            wct.setBounds(mToken, null);
+        } else {
+            final SurfaceControl.Transaction tx =
+                    mSurfaceControlTransactionFactory.getTransaction();
+            mSurfaceTransactionHelper.scale(tx, mLeash, destinationBounds,
+                    mPipBoundsState.getBounds());
+            tx.setWindowCrop(mLeash, destinationBounds.width(), destinationBounds.height());
+            // We set to fullscreen here for now, but later it will be set to UNDEFINED for
+            // the proper windowing mode to take place. See #applyWindowingModeChangeOnExit.
+            wct.setActivityWindowingMode(mToken,
+                    direction == TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN
+                            && !requestEnterSplit
+                            ? WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
+                            : WINDOWING_MODE_FULLSCREEN);
+            wct.setBounds(mToken, destinationBounds);
+            wct.setBoundsChangeTransaction(mToken, tx);
+        }
+
         // Set the exiting state first so if there is fixed rotation later, the running animation
         // won't be interrupted by alpha animation for existing PiP.
         mPipTransitionState.setTransitionState(PipTransitionState.EXITING_PIP);
 
         if (Transitions.ENABLE_SHELL_TRANSITIONS) {
-            mPipTransitionController.startTransition(destinationBounds, wct);
+            mPipTransitionController.startExitTransition(TRANSIT_EXIT_PIP, wct, destinationBounds);
             return;
         }
         mSyncTransactionQueue.queue(wct);
@@ -479,7 +512,8 @@
             wct.setBounds(mToken, null);
             wct.setWindowingMode(mToken, WINDOWING_MODE_UNDEFINED);
             wct.reorder(mToken, false);
-            mPipTransitionController.startTransition(null, wct);
+            mPipTransitionController.startExitTransition(TRANSIT_REMOVE_PIP, wct,
+                    null /* destinationBounds */);
             return;
         }
 
@@ -710,24 +744,18 @@
         if (mPipTransitionState.getTransitionState() == PipTransitionState.UNDEFINED) {
             return;
         }
+        if (Transitions.ENABLE_SHELL_TRANSITIONS
+                && mPipTransitionState.getTransitionState() == PipTransitionState.EXITING_PIP) {
+            // With Shell transition, we do the cleanup in PipTransition after exiting PIP.
+            return;
+        }
         final WindowContainerToken token = info.token;
         Objects.requireNonNull(token, "Requires valid WindowContainerToken");
         if (token.asBinder() != mToken.asBinder()) {
             Log.wtf(TAG, "Unrecognized token: " + token);
             return;
         }
-        clearWaitForFixedRotation();
-        mPipTransitionState.setInSwipePipToHomeTransition(false);
-        mPictureInPictureParams = null;
-        mPipTransitionState.setTransitionState(PipTransitionState.UNDEFINED);
-        // Re-set the PIP bounds to none.
-        mPipBoundsState.setBounds(new Rect());
-        mPipUiEventLoggerLogger.setTaskInfo(null);
-        mPipMenuController.detach();
-
-        if (info.displayId != Display.DEFAULT_DISPLAY && mOnDisplayIdChangeCallback != null) {
-            mOnDisplayIdChangeCallback.accept(Display.DEFAULT_DISPLAY);
-        }
+        onExitPipFinished(info);
 
         if (Transitions.ENABLE_SHELL_TRANSITIONS) {
             mPipTransitionController.forceFinishTransition();
@@ -824,6 +852,22 @@
         clearWaitForFixedRotation();
     }
 
+    /** Called when exiting PIP tranisiton is finished to do the state cleanup. */
+    void onExitPipFinished(TaskInfo info) {
+        clearWaitForFixedRotation();
+        mPipTransitionState.setInSwipePipToHomeTransition(false);
+        mPictureInPictureParams = null;
+        mPipTransitionState.setTransitionState(PipTransitionState.UNDEFINED);
+        // Re-set the PIP bounds to none.
+        mPipBoundsState.setBounds(new Rect());
+        mPipUiEventLoggerLogger.setTaskInfo(null);
+        mPipMenuController.detach();
+
+        if (info.displayId != Display.DEFAULT_DISPLAY && mOnDisplayIdChangeCallback != null) {
+            mOnDisplayIdChangeCallback.accept(Display.DEFAULT_DISPLAY);
+        }
+    }
+
     private void fadeExistingPip(boolean show) {
         final float alphaStart = show ? 0 : 1;
         final float alphaEnd = show ? 1 : 0;
@@ -882,7 +926,10 @@
         if (animator == null || !animator.isRunning()
                 || animator.getTransitionDirection() != TRANSITION_DIRECTION_TO_PIP) {
             final boolean rotatingPip = mPipTransitionState.isInPip() && fromRotation;
-            if (rotatingPip && mWaitForFixedRotation && mHasFadeOut) {
+            if (rotatingPip && Transitions.ENABLE_SHELL_TRANSITIONS) {
+                // The animation and surface update will be handled by the shell transition handler.
+                mPipBoundsState.setBounds(destinationBoundsOut);
+            } else if (rotatingPip && mWaitForFixedRotation && mHasFadeOut) {
                 // The position will be used by fade-in animation when the fixed rotation is done.
                 mPipBoundsState.setBounds(destinationBoundsOut);
             } else if (rotatingPip) {
@@ -1277,7 +1324,8 @@
     public void applyFinishBoundsResize(@NonNull WindowContainerTransaction wct,
             @PipAnimationController.TransitionDirection int direction, boolean wasPipTopLeft) {
         if (direction == TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN) {
-            mSplitScreenOptional.get().enterSplitScreen(mTaskInfo.taskId, wasPipTopLeft, wct);
+            mSplitScreenOptional.ifPresent(splitScreenController ->
+                    splitScreenController.enterSplitScreen(mTaskInfo.taskId, wasPipTopLeft, wct));
         } else {
             mTaskOrganizer.applyTransaction(wct);
         }
@@ -1412,7 +1460,7 @@
     /**
      * Fades out and removes an overlay surface.
      */
-    private void fadeOutAndRemoveOverlay(SurfaceControl surface, Runnable callback,
+    void fadeOutAndRemoveOverlay(SurfaceControl surface, Runnable callback,
             boolean withStartDelay) {
         if (surface == 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 0c443ce..c6794b8 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,9 +19,16 @@
 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.util.RotationUtils.rotateBounds;
+import static android.view.Surface.ROTATION_270;
+import static android.view.Surface.ROTATION_90;
+import static android.view.WindowManager.TRANSIT_CHANGE;
 import static android.view.WindowManager.TRANSIT_OPEN;
 import static android.view.WindowManager.TRANSIT_PIP;
+import static android.view.WindowManager.transitTypeToString;
+import static android.window.TransitionInfo.FLAG_IS_DISPLAY;
 import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
+import static android.window.TransitionInfo.isIndependent;
 
 import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_ALPHA;
 import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_BOUNDS;
@@ -30,19 +37,23 @@
 import static com.android.wm.shell.pip.PipAnimationController.isInPipDirection;
 import static com.android.wm.shell.pip.PipAnimationController.isOutPipDirection;
 import static com.android.wm.shell.transition.Transitions.TRANSIT_EXIT_PIP;
+import static com.android.wm.shell.transition.Transitions.TRANSIT_EXIT_PIP_TO_SPLIT;
 import static com.android.wm.shell.transition.Transitions.TRANSIT_REMOVE_PIP;
+import static com.android.wm.shell.transition.Transitions.isOpeningType;
 
 import android.app.ActivityManager;
 import android.app.TaskInfo;
 import android.content.Context;
 import android.graphics.Matrix;
+import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.IBinder;
-import android.util.Log;
+import android.util.ArrayMap;
 import android.view.Surface;
 import android.view.SurfaceControl;
 import android.window.TransitionInfo;
 import android.window.TransitionRequestInfo;
+import android.window.WindowContainerToken;
 import android.window.WindowContainerTransaction;
 
 import androidx.annotation.NonNull;
@@ -50,7 +61,11 @@
 
 import com.android.wm.shell.R;
 import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.splitscreen.SplitScreenController;
 import com.android.wm.shell.transition.Transitions;
+import com.android.wm.shell.util.CounterRotator;
+
+import java.util.Optional;
 
 /**
  * Implementation of transitions for PiP on phone. Responsible for enter (alpha, bounds) and
@@ -60,13 +75,19 @@
 
     private static final String TAG = PipTransition.class.getSimpleName();
 
+    private final Context mContext;
     private final PipTransitionState mPipTransitionState;
     private final int mEnterExitAnimationDuration;
     private final PipSurfaceTransactionHelper mSurfaceTransactionHelper;
+    private final Optional<SplitScreenController> mSplitScreenOptional;
     private @PipAnimationController.AnimationType int mOneShotAnimationType = ANIM_TYPE_BOUNDS;
     private Transitions.TransitionFinishCallback mFinishCallback;
-    private Rect mExitDestinationBounds = new Rect();
-    private IBinder mExitTransition = null;
+    private final Rect mExitDestinationBounds = new Rect();
+    @Nullable
+    private IBinder mExitTransition;
+    /** The Task window that is currently in PIP windowing mode. */
+    @Nullable
+    private WindowContainerToken mCurrentPipTaskToken;
 
     public PipTransition(Context context,
             PipBoundsState pipBoundsState,
@@ -76,13 +97,16 @@
             PipAnimationController pipAnimationController,
             Transitions transitions,
             @NonNull ShellTaskOrganizer shellTaskOrganizer,
-            PipSurfaceTransactionHelper pipSurfaceTransactionHelper) {
+            PipSurfaceTransactionHelper pipSurfaceTransactionHelper,
+            Optional<SplitScreenController> splitScreenOptional) {
         super(pipBoundsState, pipMenuController, pipBoundsAlgorithm,
                 pipAnimationController, transitions, shellTaskOrganizer);
+        mContext = context;
         mPipTransitionState = pipTransitionState;
         mEnterExitAnimationDuration = context.getResources()
                 .getInteger(R.integer.config_pipResizeAnimationDuration);
         mSurfaceTransactionHelper = pipSurfaceTransactionHelper;
+        mSplitScreenOptional = splitScreenOptional;
     }
 
     @Override
@@ -100,97 +124,66 @@
     }
 
     @Override
-    public void startTransition(Rect destinationBounds, WindowContainerTransaction out) {
+    public void startExitTransition(int type, WindowContainerTransaction out,
+            @Nullable Rect destinationBounds) {
         if (destinationBounds != null) {
             mExitDestinationBounds.set(destinationBounds);
-            mExitTransition = mTransitions.startTransition(TRANSIT_EXIT_PIP, out, this);
-        } else {
-            mTransitions.startTransition(TRANSIT_REMOVE_PIP, out, this);
         }
+        mExitTransition = mTransitions.startTransition(type, out, this);
     }
 
     @Override
-    public boolean startAnimation(@android.annotation.NonNull IBinder transition,
-            @android.annotation.NonNull TransitionInfo info,
-            @android.annotation.NonNull SurfaceControl.Transaction startTransaction,
-            @android.annotation.NonNull SurfaceControl.Transaction finishTransaction,
-            @android.annotation.NonNull Transitions.TransitionFinishCallback finishCallback) {
-
-        if (mExitTransition == transition || info.getType() == TRANSIT_EXIT_PIP) {
+    public boolean startAnimation(@NonNull IBinder transition,
+            @NonNull TransitionInfo info,
+            @NonNull SurfaceControl.Transaction startTransaction,
+            @NonNull SurfaceControl.Transaction finishTransaction,
+            @NonNull Transitions.TransitionFinishCallback finishCallback) {
+        // Exiting PIP.
+        final int type = info.getType();
+        if (transition.equals(mExitTransition)) {
+            mExitDestinationBounds.setEmpty();
             mExitTransition = null;
-            if (info.getChanges().size() == 1) {
-                if (mFinishCallback != null) {
-                    mFinishCallback.onTransitionFinished(null, null);
-                    mFinishCallback = null;
-                    throw new RuntimeException("Previous callback not called, aborting exit PIP.");
-                }
 
-                final TransitionInfo.Change change = info.getChanges().get(0);
-                mFinishCallback = finishCallback;
-                startTransaction.apply();
-                boolean success = startExpandAnimation(change.getTaskInfo(), change.getLeash(),
-                        new Rect(mExitDestinationBounds));
-                mExitDestinationBounds.setEmpty();
-                return success;
-            } else {
-                Log.e(TAG, "Got an exit-pip transition with unexpected change-list");
-            }
-        }
-
-        if (info.getType() == TRANSIT_REMOVE_PIP) {
             if (mFinishCallback != null) {
-                mFinishCallback.onTransitionFinished(null /* wct */, null /* callback */);
+                mFinishCallback.onTransitionFinished(null, null);
                 mFinishCallback = null;
-                throw new RuntimeException("Previous callback not called, aborting remove PIP.");
+                throw new RuntimeException("Previous callback not called, aborting exit PIP.");
             }
 
-            startTransaction.apply();
-            finishTransaction.setWindowCrop(info.getChanges().get(0).getLeash(),
-                    mPipBoundsState.getDisplayBounds());
-            finishCallback.onTransitionFinished(null, null);
+            final TransitionInfo.Change exitPipChange = findCurrentPipChange(info);
+            if (exitPipChange == null) {
+                throw new RuntimeException("Cannot find the pip window for exit-pip transition.");
+            }
+
+            switch (type) {
+                case TRANSIT_EXIT_PIP:
+                    startExitAnimation(info, startTransaction, finishCallback, exitPipChange);
+                    break;
+                case TRANSIT_EXIT_PIP_TO_SPLIT:
+                    startExitToSplitAnimation(info, startTransaction, finishTransaction,
+                            finishCallback, exitPipChange);
+                    break;
+                case TRANSIT_REMOVE_PIP:
+                    removePipImmediately(info, startTransaction, finishTransaction, finishCallback,
+                            exitPipChange);
+                    break;
+                default:
+                    throw new IllegalStateException("mExitTransition with unexpected transit type="
+                            + transitTypeToString(type));
+            }
+            mCurrentPipTaskToken = null;
             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;
+        // Entering PIP.
+        if (isEnteringPip(info, mCurrentPipTaskToken)) {
+            return startEnterAnimation(info, startTransaction, finishTransaction, finishCallback);
         }
 
-        // Search for an Enter PiP transition (along with a show wallpaper one)
-        TransitionInfo.Change enterPip = null;
-        TransitionInfo.Change wallpaper = null;
-        for (int i = info.getChanges().size() - 1; i >= 0; --i) {
-            final TransitionInfo.Change change = info.getChanges().get(i);
-            if (change.getTaskInfo() != null
-                    && change.getTaskInfo().configuration.windowConfiguration.getWindowingMode()
-                    == WINDOWING_MODE_PINNED) {
-                enterPip = change;
-            } else if ((change.getFlags() & FLAG_IS_WALLPAPER) != 0) {
-                wallpaper = change;
-            }
-        }
-        if (enterPip == null) {
-            return false;
-        }
-
-        if (mFinishCallback != null) {
-            mFinishCallback.onTransitionFinished(null /* wct */, null /* callback */);
-            mFinishCallback = null;
-            throw new RuntimeException("Previous callback not called, aborting entering PIP.");
-        }
-
-        // Show the wallpaper if there is a wallpaper change.
-        if (wallpaper != null) {
-            startTransaction.show(wallpaper.getLeash());
-            startTransaction.setAlpha(wallpaper.getLeash(), 1.f);
-        }
-
-        mPipTransitionState.setTransitionState(PipTransitionState.ENTERING_PIP);
-        mFinishCallback = finishCallback;
-        return startEnterAnimation(enterPip.getTaskInfo(), enterPip.getLeash(),
-                startTransaction, finishTransaction, enterPip.getStartRotation(),
-                enterPip.getEndRotation());
+        // For transition that we don't animate, we may need to update the PIP surface, otherwise it
+        // will be reset after the transition.
+        updatePipForUnhandledTransition(info, startTransaction, finishTransaction);
+        return false;
     }
 
     @Nullable
@@ -199,7 +192,6 @@
             @NonNull TransitionRequestInfo request) {
         if (request.getType() == TRANSIT_PIP) {
             WindowContainerTransaction wct = new WindowContainerTransaction();
-            mPipTransitionState.setTransitionState(PipTransitionState.ENTRY_SCHEDULED);
             if (mOneShotAnimationType == ANIM_TYPE_ALPHA) {
                 wct.setActivityWindowingMode(request.getTriggerTask().token,
                         WINDOWING_MODE_UNDEFINED);
@@ -233,6 +225,7 @@
                     new Rect(mExitDestinationBounds));
         }
         mExitDestinationBounds.setEmpty();
+        mCurrentPipTaskToken = null;
     }
 
     @Override
@@ -265,7 +258,142 @@
         mFinishCallback = null;
     }
 
-    private boolean startExpandAnimation(final TaskInfo taskInfo, final SurfaceControl leash,
+    @Nullable
+    private TransitionInfo.Change findCurrentPipChange(@NonNull TransitionInfo info) {
+        if (mCurrentPipTaskToken == null) {
+            return null;
+        }
+        for (int i = info.getChanges().size() - 1; i >= 0; --i) {
+            final TransitionInfo.Change change = info.getChanges().get(i);
+            if (mCurrentPipTaskToken.equals(change.getContainer())) {
+                return change;
+            }
+        }
+        return null;
+    }
+
+    private void startExitAnimation(@NonNull TransitionInfo info,
+            @NonNull SurfaceControl.Transaction startTransaction,
+            @NonNull Transitions.TransitionFinishCallback finishCallback,
+            @NonNull TransitionInfo.Change pipChange) {
+        TransitionInfo.Change displayRotationChange = null;
+        for (int i = info.getChanges().size() - 1; i >= 0; --i) {
+            final TransitionInfo.Change change = info.getChanges().get(i);
+            if (change.getMode() == TRANSIT_CHANGE
+                    && (change.getFlags() & FLAG_IS_DISPLAY) != 0
+                    && change.getStartRotation() != change.getEndRotation()) {
+                displayRotationChange = change;
+                break;
+            }
+        }
+
+        if (displayRotationChange != null) {
+            // Exiting PIP to fullscreen with orientation change.
+            startExpandAndRotationAnimation(info, startTransaction, finishCallback,
+                    displayRotationChange, pipChange);
+            return;
+        }
+
+        // When there is no rotation, we can simply expand the PIP window.
+        mFinishCallback = (wct, wctCB) -> {
+            mPipOrganizer.onExitPipFinished(pipChange.getTaskInfo());
+            finishCallback.onTransitionFinished(wct, wctCB);
+        };
+
+        // Set the initial frame as scaling the end to the start.
+        final Rect destinationBounds = new Rect(pipChange.getEndAbsBounds());
+        final Point offset = pipChange.getEndRelOffset();
+        destinationBounds.offset(-offset.x, -offset.y);
+        startTransaction.setWindowCrop(pipChange.getLeash(), destinationBounds);
+        mSurfaceTransactionHelper.scale(startTransaction, pipChange.getLeash(),
+                destinationBounds, mPipBoundsState.getBounds());
+        startTransaction.apply();
+        startExpandAnimation(pipChange.getTaskInfo(), pipChange.getLeash(), destinationBounds);
+    }
+
+    private void startExpandAndRotationAnimation(@NonNull TransitionInfo info,
+            @NonNull SurfaceControl.Transaction startTransaction,
+            @NonNull Transitions.TransitionFinishCallback finishCallback,
+            @NonNull TransitionInfo.Change displayRotationChange,
+            @NonNull TransitionInfo.Change pipChange) {
+        final int rotateDelta = deltaRotation(displayRotationChange.getStartRotation(),
+                displayRotationChange.getEndRotation());
+        final int displayW = displayRotationChange.getEndAbsBounds().width();
+        final int displayH = displayRotationChange.getEndAbsBounds().height();
+
+        // Counter-rotate all "going-away" things since they are still in the old orientation.
+        final ArrayMap<WindowContainerToken, CounterRotator> counterRotators = new ArrayMap<>();
+        for (int i = info.getChanges().size() - 1; i >= 0; --i) {
+            final TransitionInfo.Change change = info.getChanges().get(i);
+            if (!Transitions.isClosingType(change.getMode())
+                    || !isIndependent(change, info)
+                    || change.getParent() == null) {
+                continue;
+            }
+            CounterRotator crot = counterRotators.get(change.getParent());
+            if (crot == null) {
+                crot = new CounterRotator();
+                crot.setup(startTransaction,
+                        info.getChange(change.getParent()).getLeash(),
+                        rotateDelta, displayW, displayH);
+                if (crot.getSurface() != null) {
+                    // Wallpaper should be placed at the bottom.
+                    final int layer = (change.getFlags() & FLAG_IS_WALLPAPER) == 0
+                            ? info.getChanges().size() - i
+                            : -1;
+                    startTransaction.setLayer(crot.getSurface(), layer);
+                }
+                counterRotators.put(change.getParent(), crot);
+            }
+            crot.addChild(startTransaction, change.getLeash());
+        }
+        mFinishCallback = (wct, wctCB) -> {
+            for (int i = 0; i < counterRotators.size(); ++i) {
+                counterRotators.valueAt(i).cleanUp(info.getRootLeash());
+            }
+            mPipOrganizer.onExitPipFinished(pipChange.getTaskInfo());
+            finishCallback.onTransitionFinished(wct, wctCB);
+        };
+
+        // Get the start bounds in new orientation.
+        final Rect startBounds = new Rect(pipChange.getStartAbsBounds());
+        rotateBounds(startBounds, displayRotationChange.getStartAbsBounds(), rotateDelta);
+        final Rect endBounds = new Rect(pipChange.getEndAbsBounds());
+        final Point offset = pipChange.getEndRelOffset();
+        startBounds.offset(-offset.x, -offset.y);
+        endBounds.offset(-offset.x, -offset.y);
+
+        // Reverse the rotation direction for expansion.
+        final int pipRotateDelta = deltaRotation(rotateDelta, 0);
+
+        // Set the start frame.
+        final int degree, x, y;
+        if (pipRotateDelta == ROTATION_90) {
+            degree = 90;
+            x = startBounds.right;
+            y = startBounds.top;
+        } else {
+            degree = -90;
+            x = startBounds.left;
+            y = startBounds.bottom;
+        }
+        mSurfaceTransactionHelper.rotateAndScaleWithCrop(startTransaction, pipChange.getLeash(),
+                endBounds, startBounds, new Rect(), degree, x, y, true /* isExpanding */,
+                pipRotateDelta == ROTATION_270 /* clockwise */);
+        startTransaction.apply();
+
+        // Expand and rotate the pip window to fullscreen.
+        final PipAnimationController.PipTransitionAnimator animator =
+                mPipAnimationController.getAnimator(pipChange.getTaskInfo(), pipChange.getLeash(),
+                        startBounds, startBounds, endBounds, null, TRANSITION_DIRECTION_LEAVE_PIP,
+                        0 /* startingAngle */, pipRotateDelta);
+        animator.setTransitionDirection(TRANSITION_DIRECTION_LEAVE_PIP)
+                .setPipAnimationCallback(mPipAnimationCallback)
+                .setDuration(mEnterExitAnimationDuration)
+                .start();
+    }
+
+    private void startExpandAnimation(final TaskInfo taskInfo, final SurfaceControl leash,
             final Rect destinationBounds) {
         PipAnimationController.PipTransitionAnimator animator =
                 mPipAnimationController.getAnimator(taskInfo, leash, mPipBoundsState.getBounds(),
@@ -276,8 +404,87 @@
                 .setPipAnimationCallback(mPipAnimationCallback)
                 .setDuration(mEnterExitAnimationDuration)
                 .start();
+    }
 
-        return true;
+    /** For {@link Transitions#TRANSIT_REMOVE_PIP}, we just immediately remove the PIP Task. */
+    private void removePipImmediately(@NonNull TransitionInfo info,
+            @NonNull SurfaceControl.Transaction startTransaction,
+            @NonNull SurfaceControl.Transaction finishTransaction,
+            @NonNull Transitions.TransitionFinishCallback finishCallback,
+            @NonNull TransitionInfo.Change pipChange) {
+        startTransaction.apply();
+        finishTransaction.setWindowCrop(info.getChanges().get(0).getLeash(),
+                mPipBoundsState.getDisplayBounds());
+        mPipOrganizer.onExitPipFinished(pipChange.getTaskInfo());
+        finishCallback.onTransitionFinished(null, null);
+    }
+
+    /** Whether we should handle the given {@link TransitionInfo} animation as entering PIP. */
+    private static boolean isEnteringPip(@NonNull TransitionInfo info,
+            @Nullable WindowContainerToken currentPipTaskToken) {
+        for (int i = info.getChanges().size() - 1; i >= 0; --i) {
+            final TransitionInfo.Change change = info.getChanges().get(i);
+            if (change.getTaskInfo() != null
+                    && change.getTaskInfo().getWindowingMode() == WINDOWING_MODE_PINNED
+                    && !change.getContainer().equals(currentPipTaskToken)) {
+                // We 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 true;
+                }
+                // This can happen if the request to enter PIP happens when we are collecting for
+                // another transition, such as TRANSIT_CHANGE (display rotation).
+                if (info.getType() == TRANSIT_CHANGE) {
+                    return true;
+                }
+
+                // Please file a bug to handle the unexpected transition type.
+                throw new IllegalStateException("Entering PIP with unexpected transition type="
+                        + transitTypeToString(info.getType()));
+            }
+        }
+        return false;
+    }
+
+    private boolean startEnterAnimation(@NonNull TransitionInfo info,
+            @NonNull SurfaceControl.Transaction startTransaction,
+            @NonNull SurfaceControl.Transaction finishTransaction,
+            @NonNull Transitions.TransitionFinishCallback finishCallback) {
+        // Search for an Enter PiP transition (along with a show wallpaper one)
+        TransitionInfo.Change enterPip = null;
+        TransitionInfo.Change wallpaper = null;
+        for (int i = info.getChanges().size() - 1; i >= 0; --i) {
+            final TransitionInfo.Change change = info.getChanges().get(i);
+            if (change.getTaskInfo() != null
+                    && change.getTaskInfo().getWindowingMode() == WINDOWING_MODE_PINNED) {
+                enterPip = change;
+            } else if ((change.getFlags() & FLAG_IS_WALLPAPER) != 0) {
+                wallpaper = change;
+            }
+        }
+        if (enterPip == null) {
+            return false;
+        }
+        // Keep track of the PIP task.
+        mCurrentPipTaskToken = enterPip.getContainer();
+
+        if (mFinishCallback != null) {
+            mFinishCallback.onTransitionFinished(null /* wct */, null /* callback */);
+            mFinishCallback = null;
+            throw new RuntimeException("Previous callback not called, aborting entering PIP.");
+        }
+
+        // Show the wallpaper if there is a wallpaper change.
+        if (wallpaper != null) {
+            startTransaction.show(wallpaper.getLeash());
+            startTransaction.setAlpha(wallpaper.getLeash(), 1.f);
+        }
+
+        mPipTransitionState.setTransitionState(PipTransitionState.ENTERING_PIP);
+        mFinishCallback = finishCallback;
+        return startEnterAnimation(enterPip.getTaskInfo(), enterPip.getLeash(),
+                startTransaction, finishTransaction, enterPip.getStartRotation(),
+                enterPip.getEndRotation());
     }
 
     private boolean startEnterAnimation(final TaskInfo taskInfo, final SurfaceControl leash,
@@ -328,6 +535,11 @@
             animator = mPipAnimationController.getAnimator(taskInfo, leash, currentBounds,
                     currentBounds, destinationBounds, sourceHintRect, TRANSITION_DIRECTION_TO_PIP,
                     0 /* startingAngle */, rotationDelta);
+            if (sourceHintRect == null) {
+                // We use content overlay when there is no source rect hint to enter PiP use bounds
+                // animation.
+                animator.setUseContentOverlay(mContext);
+            }
         } else if (mOneShotAnimationType == ANIM_TYPE_ALPHA) {
             startTransaction.setAlpha(leash, 0f);
             // PiP menu is attached late in the process here to avoid any artifacts on the leash
@@ -349,6 +561,68 @@
         return true;
     }
 
+    private void startExitToSplitAnimation(TransitionInfo info,
+            SurfaceControl.Transaction startTransaction,
+            SurfaceControl.Transaction finishTransaction,
+            Transitions.TransitionFinishCallback finishCallback,
+            TransitionInfo.Change pipChange) {
+        final int changeSize = info.getChanges().size();
+        if (changeSize < 4) {
+            throw new RuntimeException(
+                    "Got an exit-pip-to-split transition with unexpected change-list");
+        }
+        for (int i = changeSize - 1; i >= 0; i--) {
+            final TransitionInfo.Change change = info.getChanges().get(i);
+            final int mode = change.getMode();
+
+            if (mode == TRANSIT_CHANGE && change.getParent() != null) {
+                // TODO: perform resize/expand animation for reparented child task.
+                continue;
+            }
+
+            if (isOpeningType(mode) && change.getParent() == null) {
+                final SurfaceControl leash = change.getLeash();
+                final Rect endBounds = change.getEndAbsBounds();
+                startTransaction
+                        .show(leash)
+                        .setAlpha(leash, 1f)
+                        .setPosition(leash, endBounds.left, endBounds.top)
+                        .setWindowCrop(leash, endBounds.width(), endBounds.height());
+            }
+        }
+        mSplitScreenOptional.get().finishEnterSplitScreen(startTransaction);
+        startTransaction.apply();
+
+        mPipOrganizer.onExitPipFinished(pipChange.getTaskInfo());
+        finishCallback.onTransitionFinished(null, null);
+    }
+
+    private void updatePipForUnhandledTransition(@NonNull TransitionInfo info,
+            @NonNull SurfaceControl.Transaction startTransaction,
+            @NonNull SurfaceControl.Transaction finishTransaction) {
+        if (mCurrentPipTaskToken == null) {
+            return;
+        }
+        for (int i = info.getChanges().size() - 1; i >= 0; --i) {
+            final TransitionInfo.Change change = info.getChanges().get(i);
+            if (!mCurrentPipTaskToken.equals(change.getContainer())) {
+                continue;
+            }
+            // When the PIP window is visible and being a part of the transition, such as display
+            // rotation, we need to update its bounds and rounded corner.
+            final SurfaceControl leash = change.getLeash();
+            final Rect destBounds = mPipBoundsState.getBounds();
+            final boolean isInPip = mPipTransitionState.isInPip();
+            mSurfaceTransactionHelper
+                    .crop(startTransaction, leash, destBounds)
+                    .round(startTransaction, leash, isInPip);
+            mSurfaceTransactionHelper
+                    .crop(finishTransaction, leash, destBounds)
+                    .round(finishTransaction, leash, isInPip);
+            break;
+        }
+    }
+
     private void finishResizeForMenu(Rect destinationBounds) {
         mPipMenuController.movePipMenu(null, null, destinationBounds);
         mPipMenuController.updateMenuBounds(destinationBounds);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
index 376f329..22b3ef3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
@@ -19,7 +19,9 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 
 import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_REMOVE_STACK;
+import static com.android.wm.shell.pip.PipAnimationController.isInPipDirection;
 
+import android.annotation.Nullable;
 import android.app.PictureInPictureParams;
 import android.app.TaskInfo;
 import android.content.ComponentName;
@@ -68,6 +70,10 @@
                     if (direction == TRANSITION_DIRECTION_REMOVE_STACK) {
                         return;
                     }
+                    if (isInPipDirection(direction) && animator.getContentOverlay() != null) {
+                        mPipOrganizer.fadeOutAndRemoveOverlay(animator.getContentOverlay(),
+                                animator::clearContentOverlay, true /* withStartDelay*/);
+                    }
                     onFinishResize(taskInfo, animator.getDestinationBounds(), direction, tx);
                     sendOnPipTransitionFinished(direction);
                 }
@@ -75,6 +81,11 @@
                 @Override
                 public void onPipAnimationCancel(TaskInfo taskInfo,
                         PipAnimationController.PipTransitionAnimator animator) {
+                    final int direction = animator.getTransitionDirection();
+                    if (isInPipDirection(direction) && animator.getContentOverlay() != null) {
+                        mPipOrganizer.fadeOutAndRemoveOverlay(animator.getContentOverlay(),
+                                animator::clearContentOverlay, true /* withStartDelay */);
+                    }
                     sendOnPipTransitionCancelled(animator.getTransitionDirection());
                 }
             };
@@ -98,9 +109,10 @@
     }
 
     /**
-     * Called when the Shell wants to starts a transition/animation.
+     * Called when the Shell wants to start an exit Pip transition/animation.
      */
-    public void startTransition(Rect destinationBounds, WindowContainerTransaction out) {
+    public void startExitTransition(int type, WindowContainerTransaction out,
+            @Nullable Rect destinationBounds) {
         // Default implementation does nothing.
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
index a006f30..7decb54 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
@@ -25,6 +25,7 @@
 import android.app.TaskInfo;
 import android.content.Context;
 import android.os.RemoteException;
+import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseIntArray;
 
@@ -291,6 +292,7 @@
          * Invalidates this instance, preventing future calls from updating the controller.
          */
         void invalidate() {
+            Slog.d("b/206648922", "invalidating controller: " + mController);
             mController = null;
         }
 
@@ -316,6 +318,8 @@
                     (controller) -> out[0] = controller.getRecentTasks(maxNum, flags, userId)
                             .toArray(new GroupedRecentTaskInfo[0]),
                     true /* blocking */);
+            Slog.d("b/206648922", "getRecentTasks(" + maxNum + "): " + out[0]
+                    + " mController=" + mController);
             return out[0];
         }
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java
index 1ba1d22..122fc9f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java
@@ -19,7 +19,6 @@
 import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.content.Context;
-import android.graphics.Rect;
 import android.view.SurfaceSession;
 import android.window.WindowContainerToken;
 import android.window.WindowContainerTransaction;
@@ -45,11 +44,6 @@
                 stageTaskUnfoldController);
     }
 
-    void moveToTop(Rect rootBounds, WindowContainerTransaction wct) {
-        final WindowContainerToken rootToken = mRootTaskInfo.token;
-        wct.setBounds(rootToken, rootBounds).reorder(rootToken, true /* onTop */);
-    }
-
     boolean removeAllTasks(WindowContainerTransaction wct, boolean toTop) {
         // No matter if the root task is empty or not, moving the root to bottom because it no
         // longer preserves visible child task.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
index a91dfe1..448773a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
@@ -76,12 +76,6 @@
     }
 
     /**
-     * Called when the keyguard occluded state changes.
-     * @param occluded Indicates if the keyguard is now occluded.
-     */
-    void onKeyguardOccludedChanged(boolean occluded);
-
-    /**
      * Called when the visibility of the keyguard changes.
      * @param showing Indicates if the keyguard is now visible.
      */
@@ -90,9 +84,6 @@
     /** Called when device waking up finished. */
     void onFinishedWakingUp();
 
-    /** Called when device going to sleep finished. */
-    void onFinishedGoingToSleep();
-
     /** Get a string representation of a stage type */
     static String stageTypeToString(@StageType int stage) {
         switch (stage) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index 18cabd3..6921448 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
@@ -26,6 +26,7 @@
 import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
 import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_SIDE;
 import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED;
+import static com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS;
 
 import android.app.ActivityManager;
 import android.app.ActivityTaskManager;
@@ -238,6 +239,15 @@
         enterSplitScreen(taskId, leftOrTop, new WindowContainerTransaction());
     }
 
+    public void prepareEnterSplitScreen(WindowContainerTransaction wct,
+            ActivityManager.RunningTaskInfo taskInfo, int startPosition) {
+        mStageCoordinator.prepareEnterSplitScreen(wct, taskInfo, startPosition);
+    }
+
+    public void finishEnterSplitScreen(SurfaceControl.Transaction t) {
+        mStageCoordinator.finishEnterSplitScreen(t);
+    }
+
     public void enterSplitScreen(int taskId, boolean leftOrTop, WindowContainerTransaction wct) {
         final int stageType = isSplitScreenVisible() ? STAGE_TYPE_UNDEFINED : STAGE_TYPE_SIDE;
         final int stagePosition =
@@ -249,10 +259,6 @@
         mStageCoordinator.exitSplitScreen(toTopTaskId, exitReason);
     }
 
-    public void onKeyguardOccludedChanged(boolean occluded) {
-        mStageCoordinator.onKeyguardOccludedChanged(occluded);
-    }
-
     public void onKeyguardVisibilityChanged(boolean showing) {
         mStageCoordinator.onKeyguardVisibilityChanged(showing);
     }
@@ -261,10 +267,6 @@
         mStageCoordinator.onFinishedWakingUp();
     }
 
-    public void onFinishedGoingToSleep() {
-        mStageCoordinator.onFinishedGoingToSleep();
-    }
-
     public void exitSplitScreenOnHide(boolean exitSplitScreenOnHide) {
         mStageCoordinator.exitSplitScreenOnHide(exitSplitScreenOnHide);
     }
@@ -318,7 +320,7 @@
 
     public void startIntent(PendingIntent intent, Intent fillInIntent, @SplitPosition int position,
             @Nullable Bundle options) {
-        if (!Transitions.ENABLE_SHELL_TRANSITIONS) {
+        if (!ENABLE_SHELL_TRANSITIONS) {
             startIntentLegacy(intent, fillInIntent, position, options);
             return;
         }
@@ -374,7 +376,8 @@
     }
 
     RemoteAnimationTarget[] onGoingToRecentsLegacy(boolean cancel, RemoteAnimationTarget[] apps) {
-        if (!isSplitScreenVisible()) return null;
+        if (ENABLE_SHELL_TRANSITIONS || apps.length < 2) return null;
+        // TODO(b/206487881): Integrate this with shell transition.
         final SurfaceControl.Builder builder = new SurfaceControl.Builder(new SurfaceSession())
                 .setContainerLayer()
                 .setName("RecentsAnimationSplitTasks")
@@ -491,13 +494,6 @@
         }
 
         @Override
-        public void onKeyguardOccludedChanged(boolean occluded) {
-            mMainExecutor.execute(() -> {
-                SplitScreenController.this.onKeyguardOccludedChanged(occluded);
-            });
-        }
-
-        @Override
         public void registerSplitScreenListener(SplitScreenListener listener, Executor executor) {
             if (mExecutors.containsKey(listener)) return;
 
@@ -538,13 +534,6 @@
                 SplitScreenController.this.onFinishedWakingUp();
             });
         }
-
-        @Override
-        public void onFinishedGoingToSleep() {
-            mMainExecutor.execute(() -> {
-                SplitScreenController.this.onFinishedGoingToSleep();
-            });
-        }
     }
 
     /**
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 54d8ece..0aa8d7e 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
@@ -28,7 +28,8 @@
 import static com.android.wm.shell.splitscreen.SplitScreenController.exitReasonToString;
 import static com.android.wm.shell.transition.Transitions.TRANSIT_SPLIT_DISMISS;
 import static com.android.wm.shell.transition.Transitions.TRANSIT_SPLIT_DISMISS_SNAP;
-import static com.android.wm.shell.transition.Transitions.isOpeningType;
+import static com.android.wm.shell.transition.Transitions.TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE;
+import static com.android.wm.shell.transition.Transitions.TRANSIT_SPLIT_SCREEN_PAIR_OPEN;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -148,7 +149,7 @@
                 t.setWindowCrop(leash, change.getEndAbsBounds().width(),
                         change.getEndAbsBounds().height());
             }
-            boolean isOpening = isOpeningType(info.getType());
+            boolean isOpening = isOpeningTransition(info);
             if (isOpening && (mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT)) {
                 // fade in
                 startExampleAnimation(leash, true /* show */);
@@ -305,6 +306,12 @@
         mTransitions.getAnimExecutor().execute(va::start);
     }
 
+    private boolean isOpeningTransition(TransitionInfo info) {
+        return Transitions.isOpeningType(info.getType())
+                || info.getType() == TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE
+                || info.getType() == TRANSIT_SPLIT_SCREEN_PAIR_OPEN;
+    }
+
     /** Bundled information of dismiss transition. */
     static class DismissTransition {
         IBinder mTransition;
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 d217686..83830ec 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
@@ -46,7 +46,7 @@
 import static com.android.wm.shell.splitscreen.SplitScreenController.exitReasonToString;
 import static com.android.wm.shell.splitscreen.SplitScreenTransitions.FLAG_IS_DIVIDER_BAR;
 import static com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS;
-import static com.android.wm.shell.transition.Transitions.TRANSIT_SPLIT_DISMISS_SNAP;
+import static com.android.wm.shell.transition.Transitions.TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE;
 import static com.android.wm.shell.transition.Transitions.TRANSIT_SPLIT_SCREEN_PAIR_OPEN;
 import static com.android.wm.shell.transition.Transitions.isClosingType;
 import static com.android.wm.shell.transition.Transitions.isOpeningType;
@@ -58,6 +58,7 @@
 import android.app.ActivityTaskManager;
 import android.app.WindowConfiguration;
 import android.content.Context;
+import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.hardware.devicestate.DeviceStateManager;
 import android.os.Bundle;
@@ -88,6 +89,7 @@
 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.SyncTransactionQueue;
 import com.android.wm.shell.common.TransactionPool;
 import com.android.wm.shell.common.split.SplitLayout;
@@ -134,6 +136,7 @@
     private final SideStage mSideStage;
     private final StageListenerImpl mSideStageListener = new StageListenerImpl();
     private final StageTaskUnfoldController mSideUnfoldController;
+    private final DisplayLayout mDisplayLayout;
     @SplitPosition
     private int mSideStagePosition = SPLIT_POSITION_BOTTOM_OR_RIGHT;
 
@@ -157,8 +160,6 @@
     // and exit, since exit itself can trigger a number of changes that update the stages.
     private boolean mShouldUpdateRecents;
     private boolean mExitSplitScreenOnHide;
-    private boolean mKeyguardOccluded;
-    private boolean mDeviceSleep;
 
     /** The target stage to dismiss to when unlock after folded. */
     @StageType
@@ -171,6 +172,7 @@
             // properly for the animation itself.
             mSplitLayout.release();
             mSplitLayout.resetDividerPosition();
+            mTopStageAfterFoldDismiss = STAGE_TYPE_UNDEFINED;
         }
     };
 
@@ -236,6 +238,7 @@
         mSplitTransitions = new SplitScreenTransitions(transactionPool, transitions,
                 mOnTransitionAnimationComplete);
         mDisplayController.addDisplayWindowListener(this);
+        mDisplayLayout = new DisplayLayout(displayController.getDisplayLayout(displayId));
         transitions.addHandler(this);
     }
 
@@ -269,6 +272,7 @@
         mLogger = logger;
         mRecentTasks = recentTasks;
         mDisplayController.addDisplayWindowListener(this);
+        mDisplayLayout = new DisplayLayout();
         transitions.addHandler(this);
     }
 
@@ -320,7 +324,14 @@
         if (!evictWct.isEmpty()) {
             wct.merge(evictWct, true /* transfer */);
         }
-        mTaskOrganizer.applyTransaction(wct);
+
+        if (ENABLE_SHELL_TRANSITIONS) {
+            prepareEnterSplitScreen(wct);
+            mSplitTransitions.startEnterTransition(TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE,
+                    wct, null, this);
+        } else {
+            mTaskOrganizer.applyTransaction(wct);
+        }
         return true;
     }
 
@@ -369,7 +380,14 @@
     void startTasksWithLegacyTransition(int mainTaskId, @Nullable Bundle mainOptions,
             int sideTaskId, @Nullable Bundle sideOptions, @SplitPosition int sidePosition,
             float splitRatio, RemoteAnimationAdapter adapter) {
+        // Init divider first to make divider leash for remote animation target.
+        mSplitLayout.init();
+        // Set false to avoid record new bounds with old task still on top;
+        mShouldUpdateRecents = false;
         final WindowContainerTransaction wct = new WindowContainerTransaction();
+        final WindowContainerTransaction evictWct = new WindowContainerTransaction();
+        prepareEvictChildTasks(SPLIT_POSITION_TOP_OR_LEFT, evictWct);
+        prepareEvictChildTasks(SPLIT_POSITION_BOTTOM_OR_RIGHT, evictWct);
         // Need to add another wrapper here in shell so that we can inject the divider bar
         // and also manage the process elevation via setRunningRemote
         IRemoteAnimationRunner wrapper = new IRemoteAnimationRunner.Stub() {
@@ -385,6 +403,17 @@
                     augmentedNonApps[i] = nonApps[i];
                 }
                 augmentedNonApps[augmentedNonApps.length - 1] = getDividerBarLegacyTarget();
+
+                IRemoteAnimationFinishedCallback wrapCallback =
+                        new IRemoteAnimationFinishedCallback.Stub() {
+                            @Override
+                            public void onAnimationFinished() throws RemoteException {
+                                mShouldUpdateRecents = true;
+                                mSyncQueue.queue(evictWct);
+                                mSyncQueue.runInSync(t -> setDividerVisibility(true, t));
+                                finishedCallback.onAnimationFinished();
+                            }
+                        };
                 try {
                     try {
                         ActivityTaskManager.getService().setRunningRemoteTransitionDelegate(
@@ -393,8 +422,8 @@
                         Slog.e(TAG, "Unable to boost animation thread. This should only happen"
                                 + " during unit tests");
                     }
-                    adapter.getRunner().onAnimationStart(transit, apps, wallpapers, nonApps,
-                            finishedCallback);
+                    adapter.getRunner().onAnimationStart(transit, apps, wallpapers,
+                            augmentedNonApps, wrapCallback);
                 } catch (RemoteException e) {
                     Slog.e(TAG, "Error starting remote animation", e);
                 }
@@ -402,6 +431,9 @@
 
             @Override
             public void onAnimationCancelled() {
+                mShouldUpdateRecents = true;
+                mSyncQueue.queue(evictWct);
+                mSyncQueue.runInSync(t -> setDividerVisibility(true, t));
                 try {
                     adapter.getRunner().onAnimationCancelled();
                 } catch (RemoteException e) {
@@ -424,10 +456,14 @@
         setSideStagePosition(sidePosition, wct);
 
         mSplitLayout.setDivideRatio(splitRatio);
-        // Build a request WCT that will launch both apps such that task 0 is on the main stage
-        // while task 1 is on the side stage.
-        mMainStage.activate(getMainStageBounds(), wct, false /* reparent */);
-        mSideStage.setBounds(getSideStageBounds(), wct);
+        if (mMainStage.isActive()) {
+            mMainStage.moveToTop(getMainStageBounds(), wct);
+        } else {
+            // Build a request WCT that will launch both apps such that task 0 is on the main stage
+            // while task 1 is on the side stage.
+            mMainStage.activate(getMainStageBounds(), wct, false /* reparent */);
+        }
+        mSideStage.moveToTop(getSideStageBounds(), wct);
 
         // Make sure the launch options will put tasks in the corresponding split roots
         addActivityOptions(mainOptions, mMainStage);
@@ -554,29 +590,54 @@
         mTaskOrganizer.applyTransaction(wct);
     }
 
-    void onKeyguardOccludedChanged(boolean occluded) {
-        // Do not exit split directly, because it needs to wait for task info update to determine
-        // which task should remain on top after split dismissed.
-        mKeyguardOccluded = occluded;
-    }
-
     void onKeyguardVisibilityChanged(boolean showing) {
-        if (!showing && mMainStage.isActive()
-                && mTopStageAfterFoldDismiss != STAGE_TYPE_UNDEFINED) {
-            exitSplitScreen(mTopStageAfterFoldDismiss == STAGE_TYPE_MAIN ? mMainStage : mSideStage,
-                    EXIT_REASON_DEVICE_FOLDED);
+        if (!mMainStage.isActive()) {
+            return;
+        }
+
+        if (ENABLE_SHELL_TRANSITIONS) {
+            // Update divider visibility so it won't float on top of keyguard.
+            setDividerVisibility(!showing, null /* transaction */);
+        }
+
+        if (!showing && mTopStageAfterFoldDismiss != STAGE_TYPE_UNDEFINED) {
+            if (ENABLE_SHELL_TRANSITIONS) {
+                final WindowContainerTransaction wct = new WindowContainerTransaction();
+                prepareExitSplitScreen(mTopStageAfterFoldDismiss, wct);
+                mSplitTransitions.startDismissTransition(null /* transition */, wct, this,
+                        mTopStageAfterFoldDismiss, EXIT_REASON_DEVICE_FOLDED);
+            } else {
+                exitSplitScreen(
+                        mTopStageAfterFoldDismiss == STAGE_TYPE_MAIN ? mMainStage : mSideStage,
+                        EXIT_REASON_DEVICE_FOLDED);
+            }
         }
     }
 
     void onFinishedWakingUp() {
-        if (mMainStage.isActive()) {
-            exitSplitScreenIfKeyguardOccluded();
+        if (!mMainStage.isActive()) {
+            return;
         }
-        mDeviceSleep = false;
-    }
 
-    void onFinishedGoingToSleep() {
-        mDeviceSleep = true;
+        // Check if there's only one stage visible while keyguard occluded.
+        final boolean mainStageVisible = mMainStage.mRootTaskInfo.isVisible;
+        final boolean oneStageVisible =
+                mMainStage.mRootTaskInfo.isVisible != mSideStage.mRootTaskInfo.isVisible;
+        if (oneStageVisible) {
+            // Dismiss split because there's show-when-locked activity showing on top of keyguard.
+            // Also make sure the task contains show-when-locked activity remains on top after split
+            // dismissed.
+            if (!ENABLE_SHELL_TRANSITIONS) {
+                final StageTaskListener toTop = mainStageVisible ? mMainStage : mSideStage;
+                exitSplitScreen(toTop, EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP);
+            } else {
+                final int dismissTop = mainStageVisible ? STAGE_TYPE_MAIN : STAGE_TYPE_SIDE;
+                final WindowContainerTransaction wct = new WindowContainerTransaction();
+                prepareExitSplitScreen(dismissTop, wct);
+                mSplitTransitions.startDismissTransition(null /* transition */, wct, this,
+                        dismissTop, EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP);
+            }
+        }
     }
 
     void exitSplitScreenOnHide(boolean exitSplitScreenOnHide) {
@@ -607,19 +668,6 @@
         applyExitSplitScreen(childrenToTop, wct, exitReason);
     }
 
-    private void exitSplitScreenIfKeyguardOccluded() {
-        final boolean mainStageVisible = mMainStageListener.mVisible;
-        final boolean oneStageVisible = mainStageVisible ^ mSideStageListener.mVisible;
-        if (mDeviceSleep && mKeyguardOccluded && oneStageVisible) {
-            // Only the stages include show-when-locked activity is visible while keyguard occluded.
-            // Dismiss split because there's show-when-locked activity showing on top of keyguard.
-            // Also make sure the task contains show-when-locked activity remains on top after split
-            // dismissed.
-            final StageTaskListener toTop = mainStageVisible ? mMainStage : mSideStage;
-            exitSplitScreen(toTop, EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP);
-        }
-    }
-
     private void applyExitSplitScreen(StageTaskListener childrenToTop,
             WindowContainerTransaction wct, @ExitReason int exitReason) {
         mRecentTasks.ifPresent(recentTasks -> {
@@ -669,6 +717,10 @@
             case EXIT_REASON_APP_FINISHED:
             // One of the children enters PiP
             case EXIT_REASON_CHILD_TASK_ENTER_PIP:
+            // One of the apps occludes lock screen.
+            case EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP:
+            // User has unlocked the device after folded
+            case EXIT_REASON_DEVICE_FOLDED:
                 return true;
             default:
                 return false;
@@ -680,12 +732,47 @@
      * an existing WindowContainerTransaction (rather than applying immediately). This is intended
      * to be used when exiting split might be bundled with other window operations.
      */
-    void prepareExitSplitScreen(@StageType int stageToTop,
+    private void prepareExitSplitScreen(@StageType int stageToTop,
             @NonNull WindowContainerTransaction wct) {
+        if (!mMainStage.isActive()) return;
         mSideStage.removeAllTasks(wct, stageToTop == STAGE_TYPE_SIDE);
         mMainStage.deactivate(wct, stageToTop == STAGE_TYPE_MAIN);
     }
 
+    private void prepareEnterSplitScreen(WindowContainerTransaction wct) {
+        prepareEnterSplitScreen(wct, null /* taskInfo */, SPLIT_POSITION_UNDEFINED);
+    }
+
+    /**
+     * Prepare transaction to active split screen. If there's a task indicated, the task will be put
+     * into side stage.
+     */
+    void prepareEnterSplitScreen(WindowContainerTransaction wct,
+            @Nullable ActivityManager.RunningTaskInfo taskInfo, @SplitPosition int startPosition) {
+        if (mMainStage.isActive()) return;
+
+        if (taskInfo != null) {
+            setSideStagePosition(startPosition, wct);
+            mSideStage.addTask(taskInfo, wct);
+        }
+        mMainStage.activate(getMainStageBounds(), wct, true /* includingTopTask */);
+        mSideStage.moveToTop(getSideStageBounds(), wct);
+    }
+
+    void finishEnterSplitScreen(SurfaceControl.Transaction t) {
+        mSplitLayout.init();
+        setDividerVisibility(true, t);
+        setSplitsVisible(true);
+        mShouldUpdateRecents = true;
+        updateRecentTasksSplitPair();
+        if (!mLogger.hasStartedSession()) {
+            mLogger.logEnter(mSplitLayout.getDividerPositionAsFraction(),
+                    getMainStagePosition(), mMainStage.getTopChildTaskUid(),
+                    getSideStagePosition(), mSideStage.getTopChildTaskUid(),
+                    mSplitLayout.isLandscape());
+        }
+    }
+
     void getStageBounds(Rect outTopOrLeftBounds, Rect outBottomOrRightBounds) {
         outTopOrLeftBounds.set(mSplitLayout.getBounds1());
         outBottomOrRightBounds.set(mSplitLayout.getBounds2());
@@ -751,7 +838,9 @@
             mLogger.logSideStageAppChange(getSideStagePosition(), mSideStage.getTopChildTaskUid(),
                     mSplitLayout.isLandscape());
         }
-        updateRecentTasksSplitPair();
+        if (present && visible) {
+            updateRecentTasksSplitPair();
+        }
 
         for (int i = mListeners.size() - 1; i >= 0; --i) {
             mListeners.get(i).onTaskStageChanged(taskId, stage, visible);
@@ -767,7 +856,6 @@
         if (!mShouldUpdateRecents) {
             return;
         }
-
         mRecentTasks.ifPresent(recentTasks -> {
             Rect topLeftBounds = mSplitLayout.getBounds1();
             Rect bottomRightBounds = mSplitLayout.getBounds2();
@@ -828,31 +916,27 @@
     private void onStageVisibilityChanged(StageListenerImpl stageListener) {
         final boolean sideStageVisible = mSideStageListener.mVisible;
         final boolean mainStageVisible = mMainStageListener.mVisible;
-        final boolean bothStageVisible = sideStageVisible && mainStageVisible;
-        final boolean bothStageInvisible = !sideStageVisible && !mainStageVisible;
-        final boolean sameVisibility = sideStageVisible == mainStageVisible;
 
-        if (bothStageInvisible) {
+        // Wait for both stages having the same visibility to prevent causing flicker.
+        if (mainStageVisible != sideStageVisible) {
+            return;
+        }
+
+        if (!mainStageVisible) {
+            // Both stages are not visible, check if it needs to dismiss split screen.
             if (mExitSplitScreenOnHide
-                    // Don't dismiss staged split when both stages are not visible due to sleeping
-                    // display, like the cases keyguard showing or screen off.
+                    // Don't dismiss split screen when both stages are not visible due to sleeping
+                    // display.
                     || (!mMainStage.mRootTaskInfo.isSleeping
                     && !mSideStage.mRootTaskInfo.isSleeping)) {
-            // Don't dismiss staged split when both stages are not visible due to sleeping display,
-            // like the cases keyguard showing or screen off.
                 exitSplitScreen(null /* childrenToTop */, EXIT_REASON_RETURN_HOME);
             }
         }
-        exitSplitScreenIfKeyguardOccluded();
 
         mSyncQueue.runInSync(t -> {
-            // Same above, we only set root tasks and divider leash visibility when both stage
-            // change to visible or invisible to avoid flicker.
-            if (sameVisibility) {
-                t.setVisibility(mSideStage.mRootLeash, bothStageVisible)
-                        .setVisibility(mMainStage.mRootLeash, bothStageVisible);
-                setDividerVisibility(bothStageVisible, t);
-            }
+            t.setVisibility(mSideStage.mRootLeash, sideStageVisible)
+                    .setVisibility(mMainStage.mRootLeash, mainStageVisible);
+            setDividerVisibility(mainStageVisible, t);
         });
     }
 
@@ -868,12 +952,11 @@
 
     private void applyDividerVisibility(SurfaceControl.Transaction t) {
         final SurfaceControl dividerLeash = mSplitLayout.getDividerLeash();
-        if (dividerLeash == null) {
-            return;
-        }
+        if (dividerLeash == null) return;
 
         if (mDividerVisible) {
             t.show(dividerLeash);
+            t.setAlpha(dividerLeash, 1);
             t.setLayer(dividerLeash, SPLIT_DIVIDER_LAYER);
             t.setPosition(dividerLeash,
                     mSplitLayout.getDividerBounds().left, mSplitLayout.getDividerBounds().top);
@@ -895,11 +978,14 @@
             }
         } else if (isSideStage) {
             final WindowContainerTransaction wct = new WindowContainerTransaction();
+            mSplitLayout.init();
             // Make sure the main stage is active.
-            mMainStage.activate(getMainStageBounds(), wct, true /* reparent */);
-            mSideStage.moveToTop(getSideStageBounds(), wct);
+            prepareEnterSplitScreen(wct);
             mSyncQueue.queue(wct);
-            mSyncQueue.runInSync(t -> updateSurfaceBounds(mSplitLayout, t));
+            mSyncQueue.runInSync(t -> {
+                updateSurfaceBounds(mSplitLayout, t);
+                setDividerVisibility(true, t);
+            });
         }
         if (mMainStageListener.mHasChildren && mSideStageListener.mHasChildren) {
             mShouldUpdateRecents = true;
@@ -1074,6 +1160,14 @@
         mDisplayController.addDisplayChangingController(this::onRotateDisplay);
     }
 
+    @Override
+    public void onDisplayConfigurationChanged(int displayId, Configuration newConfig) {
+        if (displayId != DEFAULT_DISPLAY) {
+            return;
+        }
+        mDisplayLayout.set(mDisplayController.getDisplayLayout(displayId));
+    }
+
     private void onRotateDisplay(int displayId, int fromRotation, int toRotation,
             WindowContainerTransaction wct) {
         if (!mMainStage.isActive()) return;
@@ -1082,7 +1176,8 @@
 
         final SurfaceControl.Transaction t = mTransactionPool.acquire();
         setDividerVisibility(false, t);
-        mSplitLayout.rotateTo(toRotation);
+        mDisplayLayout.rotateTo(mContext.getResources(), toRotation);
+        mSplitLayout.rotateTo(toRotation, mDisplayLayout.stableInsets());
         updateWindowBounds(mSplitLayout, wct);
         updateUnfoldBounds();
         t.apply();
@@ -1189,8 +1284,7 @@
             if (isOpening && getStageOfTask(triggerTask) != null) {
                 // One task is appearing into split, prepare to enter split screen.
                 out = new WindowContainerTransaction();
-                mMainStage.activate(getMainStageBounds(), out, true /* includingTopTask */);
-                mSideStage.moveToTop(getSideStageBounds(), out);
+                prepareEnterSplitScreen(out);
                 mSplitTransitions.mPendingEnter = transition;
             }
         }
@@ -1198,6 +1292,16 @@
     }
 
     @Override
+    public void onTransitionMerged(@NonNull IBinder transition) {
+        // Once the pending enter transition got merged, make sure to bring divider bar visible and
+        // clear the pending transition from cache to prevent mess-up the following state.
+        if (transition == mSplitTransitions.mPendingEnter) {
+            finishEnterSplitScreen(null);
+            mSplitTransitions.mPendingEnter = null;
+        }
+    }
+
+    @Override
     public boolean startAnimation(@NonNull IBinder transition,
             @NonNull TransitionInfo info,
             @NonNull SurfaceControl.Transaction startTransaction,
@@ -1280,47 +1384,40 @@
                 sideChild = change;
             }
         }
-        if (mainChild == null || sideChild == null) {
-            throw new IllegalStateException("Launched 2 tasks in split, but didn't receive"
-                    + " 2 tasks in transition. Possibly one of them failed to launch");
-            // TODO: fallback logic. Probably start a new transition to exit split before
-            //       applying anything here. Ideally consolidate with transition-merging.
+
+        // TODO: fallback logic. Probably start a new transition to exit split before applying
+        //       anything here. Ideally consolidate with transition-merging.
+        if (info.getType() == TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE) {
+            if (mainChild == null && sideChild == null) {
+                throw new IllegalStateException("Launched a task in split, but didn't receive any"
+                        + " task in transition.");
+            }
+        } else {
+            if (mainChild == null || sideChild == null) {
+                throw new IllegalStateException("Launched 2 tasks in split, but didn't receive"
+                        + " 2 tasks in transition. Possibly one of them failed to launch");
+            }
         }
 
-        // Update local states (before animating).
-        mSplitLayout.init();
-        setDividerVisibility(true, t);
-        setSplitsVisible(true);
-
-        addDividerBarToTransition(info, t, true /* show */);
-
         // Make some noise if things aren't totally expected. These states shouldn't effect
         // transitions locally, but remotes (like Launcher) may get confused if they were
         // depending on listener callbacks. This can happen because task-organizer callbacks
         // aren't serialized with transition callbacks.
         // TODO(b/184679596): Find a way to either include task-org information in
         //                    the transition, or synchronize task-org callbacks.
-        if (!mMainStage.containsTask(mainChild.getTaskInfo().taskId)) {
+        if (mainChild != null && !mMainStage.containsTask(mainChild.getTaskInfo().taskId)) {
             Log.w(TAG, "Expected onTaskAppeared on " + mMainStage
                     + " to have been called with " + mainChild.getTaskInfo().taskId
                     + " before startAnimation().");
         }
-        if (!mSideStage.containsTask(sideChild.getTaskInfo().taskId)) {
+        if (sideChild != null && !mSideStage.containsTask(sideChild.getTaskInfo().taskId)) {
             Log.w(TAG, "Expected onTaskAppeared on " + mSideStage
                     + " to have been called with " + sideChild.getTaskInfo().taskId
                     + " before startAnimation().");
         }
 
-        mShouldUpdateRecents = true;
-        updateRecentTasksSplitPair();
-
-        if (!mLogger.hasStartedSession()) {
-            mLogger.logEnter(mSplitLayout.getDividerPositionAsFraction(),
-                    getMainStagePosition(), mMainStage.getTopChildTaskUid(),
-                    getSideStagePosition(), mSideStage.getTopChildTaskUid(),
-                    mSplitLayout.isLandscape());
-        }
-
+        finishEnterSplitScreen(t);
+        addDividerBarToTransition(info, t, true /* show */);
         return true;
     }
 
@@ -1374,11 +1471,9 @@
         setSplitsVisible(false);
         // Wait until after animation to update divider
 
-        if (info.getType() == TRANSIT_SPLIT_DISMISS_SNAP) {
-            // Reset crops so they don't interfere with subsequent launches
-            t.setWindowCrop(mMainStage.mRootLeash, null);
-            t.setWindowCrop(mSideStage.mRootLeash, null);
-        }
+        // Reset crops so they don't interfere with subsequent launches
+        t.setWindowCrop(mMainStage.mRootLeash, null);
+        t.setWindowCrop(mSideStage.mRootLeash, null);
 
         if (dismissTransition.mDismissTop == STAGE_TYPE_UNDEFINED) {
             logExit(dismissTransition.mReason);
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 2c853c1..83534c1 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
@@ -34,6 +34,7 @@
 import android.util.SparseArray;
 import android.view.SurfaceControl;
 import android.view.SurfaceSession;
+import android.window.WindowContainerToken;
 import android.window.WindowContainerTransaction;
 
 import androidx.annotation.NonNull;
@@ -301,9 +302,19 @@
     }
 
     void addTask(ActivityManager.RunningTaskInfo task, WindowContainerTransaction wct) {
+        // Clear overridden bounds and windowing mode to make sure the child task can inherit
+        // windowing mode and bounds from split root.
+        wct.setWindowingMode(task.token, WINDOWING_MODE_UNDEFINED)
+                .setBounds(task.token, null);
+
         wct.reparent(task.token, mRootTaskInfo.token, true /* onTop*/);
     }
 
+    void moveToTop(Rect rootBounds, WindowContainerTransaction wct) {
+        final WindowContainerToken rootToken = mRootTaskInfo.token;
+        wct.setBounds(rootToken, rootBounds).reorder(rootToken, true /* onTop */);
+    }
+
     void setBounds(Rect bounds, WindowContainerTransaction wct) {
         wct.setBounds(mRootTaskInfo.token, bounds);
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskUnfoldController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskUnfoldController.java
index 0683a25..59eecb5d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskUnfoldController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskUnfoldController.java
@@ -105,6 +105,9 @@
      * @param leash surface leash for the appeared task
      */
     public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) {
+        // Only handle child task surface here.
+        if (!taskInfo.hasParentTask()) return;
+
         AnimationContext context = new AnimationContext(leash);
         mAnimationContextByTaskId.put(taskInfo.taskId, context);
     }
@@ -114,6 +117,8 @@
      * @param taskInfo info for the vanished task
      */
     public void onTaskVanished(ActivityManager.RunningTaskInfo taskInfo) {
+        if (!taskInfo.hasParentTask()) return;
+
         AnimationContext context = mAnimationContextByTaskId.get(taskInfo.taskId);
         if (context != null) {
             final SurfaceControl.Transaction transaction = mTransactionPool.acquire();
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 324b8b5..072b925 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
@@ -18,11 +18,13 @@
 
 import static android.app.ActivityOptions.ANIM_CLIP_REVEAL;
 import static android.app.ActivityOptions.ANIM_CUSTOM;
+import static android.app.ActivityOptions.ANIM_FROM_STYLE;
 import static android.app.ActivityOptions.ANIM_NONE;
 import static android.app.ActivityOptions.ANIM_OPEN_CROSS_PROFILE_APPS;
 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.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 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;
@@ -356,6 +358,12 @@
                     continue;
                 }
 
+                // There is no default animation for Pip window in rotation transition, and the
+                // PipTransition will update the surface of its own window at start/finish.
+                if (isTask && change.getTaskInfo().configuration.windowConfiguration
+                        .getWindowingMode() == WINDOWING_MODE_PINNED) {
+                    continue;
+                }
                 // No default animation for this, so just update bounds/position.
                 startTransaction.setPosition(change.getLeash(),
                         change.getEndAbsBounds().left - info.getRootOffset().x,
@@ -509,60 +517,70 @@
         } else if ((changeFlags & FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT) != 0 && isOpeningType) {
             // This received a transferred starting window, so don't animate
             return null;
-        } else if (wallpaperTransit == WALLPAPER_TRANSITION_INTRA_OPEN) {
-            a = mTransitionAnimation.loadDefaultAnimationAttr(enter
-                    ? R.styleable.WindowAnimation_wallpaperIntraOpenEnterAnimation
-                    : R.styleable.WindowAnimation_wallpaperIntraOpenExitAnimation);
-        } else if (wallpaperTransit == WALLPAPER_TRANSITION_INTRA_CLOSE) {
-            a = mTransitionAnimation.loadDefaultAnimationAttr(enter
-                    ? R.styleable.WindowAnimation_wallpaperIntraCloseEnterAnimation
-                    : R.styleable.WindowAnimation_wallpaperIntraCloseExitAnimation);
-        } else if (wallpaperTransit == WALLPAPER_TRANSITION_OPEN) {
-            a = mTransitionAnimation.loadDefaultAnimationAttr(enter
-                    ? R.styleable.WindowAnimation_wallpaperOpenEnterAnimation
-                    : R.styleable.WindowAnimation_wallpaperOpenExitAnimation);
-        } else if (wallpaperTransit == WALLPAPER_TRANSITION_CLOSE) {
-            a = mTransitionAnimation.loadDefaultAnimationAttr(enter
-                    ? R.styleable.WindowAnimation_wallpaperCloseEnterAnimation
-                    : R.styleable.WindowAnimation_wallpaperCloseExitAnimation);
-        } else if (type == TRANSIT_OPEN) {
-            if (isTask) {
-                a = mTransitionAnimation.loadDefaultAnimationAttr(enter
-                        ? R.styleable.WindowAnimation_taskOpenEnterAnimation
-                        : R.styleable.WindowAnimation_taskOpenExitAnimation);
-            } else {
-                if ((changeFlags & FLAG_TRANSLUCENT) != 0 && enter) {
-                    a = mTransitionAnimation.loadDefaultAnimationRes(
-                            R.anim.activity_translucent_open_enter);
+        } else {
+            int animAttr = 0;
+            boolean translucent = false;
+            if (wallpaperTransit == WALLPAPER_TRANSITION_INTRA_OPEN) {
+                animAttr = enter
+                        ? R.styleable.WindowAnimation_wallpaperIntraOpenEnterAnimation
+                        : R.styleable.WindowAnimation_wallpaperIntraOpenExitAnimation;
+            } else if (wallpaperTransit == WALLPAPER_TRANSITION_INTRA_CLOSE) {
+                animAttr = enter
+                        ? R.styleable.WindowAnimation_wallpaperIntraCloseEnterAnimation
+                        : R.styleable.WindowAnimation_wallpaperIntraCloseExitAnimation;
+            } else if (wallpaperTransit == WALLPAPER_TRANSITION_OPEN) {
+                animAttr = enter
+                        ? R.styleable.WindowAnimation_wallpaperOpenEnterAnimation
+                        : R.styleable.WindowAnimation_wallpaperOpenExitAnimation;
+            } else if (wallpaperTransit == WALLPAPER_TRANSITION_CLOSE) {
+                animAttr = enter
+                        ? R.styleable.WindowAnimation_wallpaperCloseEnterAnimation
+                        : R.styleable.WindowAnimation_wallpaperCloseExitAnimation;
+            } else if (type == TRANSIT_OPEN) {
+                if (isTask) {
+                    animAttr = enter
+                            ? R.styleable.WindowAnimation_taskOpenEnterAnimation
+                            : R.styleable.WindowAnimation_taskOpenExitAnimation;
                 } else {
-                    a = mTransitionAnimation.loadDefaultAnimationAttr(enter
+                    if ((changeFlags & FLAG_TRANSLUCENT) != 0 && enter) {
+                        translucent = true;
+                    }
+                    animAttr = enter
                             ? R.styleable.WindowAnimation_activityOpenEnterAnimation
-                            : R.styleable.WindowAnimation_activityOpenExitAnimation);
+                            : R.styleable.WindowAnimation_activityOpenExitAnimation;
                 }
-            }
-        } else if (type == TRANSIT_TO_FRONT) {
-            a = mTransitionAnimation.loadDefaultAnimationAttr(enter
-                    ? R.styleable.WindowAnimation_taskToFrontEnterAnimation
-                    : R.styleable.WindowAnimation_taskToFrontExitAnimation);
-        } else if (type == TRANSIT_CLOSE) {
-            if (isTask) {
-                a = mTransitionAnimation.loadDefaultAnimationAttr(enter
-                        ? R.styleable.WindowAnimation_taskCloseEnterAnimation
-                        : R.styleable.WindowAnimation_taskCloseExitAnimation);
-            } else {
-                if ((changeFlags & FLAG_TRANSLUCENT) != 0 && !enter) {
-                    a = mTransitionAnimation.loadDefaultAnimationRes(
-                            R.anim.activity_translucent_close_exit);
+            } else if (type == TRANSIT_TO_FRONT) {
+                animAttr = enter
+                        ? R.styleable.WindowAnimation_taskToFrontEnterAnimation
+                        : R.styleable.WindowAnimation_taskToFrontExitAnimation;
+            } else if (type == TRANSIT_CLOSE) {
+                if (isTask) {
+                    animAttr = enter
+                            ? R.styleable.WindowAnimation_taskCloseEnterAnimation
+                            : R.styleable.WindowAnimation_taskCloseExitAnimation;
                 } else {
-                    a = mTransitionAnimation.loadDefaultAnimationAttr(enter
+                    if ((changeFlags & FLAG_TRANSLUCENT) != 0 && !enter) {
+                        translucent = true;
+                    }
+                    animAttr = enter
                             ? R.styleable.WindowAnimation_activityCloseEnterAnimation
-                            : R.styleable.WindowAnimation_activityCloseExitAnimation);
+                            : R.styleable.WindowAnimation_activityCloseExitAnimation;
+                }
+            } else if (type == TRANSIT_TO_BACK) {
+                animAttr = enter
+                        ? R.styleable.WindowAnimation_taskToBackEnterAnimation
+                        : R.styleable.WindowAnimation_taskToBackExitAnimation;
+            }
+
+            if (animAttr != 0) {
+                if (overrideType == ANIM_FROM_STYLE && canCustomContainer) {
+                    a = mTransitionAnimation
+                            .loadAnimationAttr(options.getPackageName(), options.getAnimations(),
+                                    animAttr, translucent);
+                } else {
+                    a = mTransitionAnimation.loadDefaultAnimationAttr(animAttr);
                 }
             }
-        } else if (type == TRANSIT_TO_BACK) {
-            a = mTransitionAnimation.loadDefaultAnimationAttr(enter
-                    ? R.styleable.WindowAnimation_taskToBackEnterAnimation
-                    : R.styleable.WindowAnimation_taskToBackExitAnimation);
         }
 
         if (a != null) {
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 b8cbfd9..33a98b2 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
@@ -74,23 +74,25 @@
     public static final boolean ENABLE_SHELL_TRANSITIONS =
             SystemProperties.getBoolean("persist.debug.shell_transit", false);
 
-    /** Transition type for dismissing split-screen via dragging the divider off the screen. */
-    public static final int TRANSIT_SPLIT_DISMISS_SNAP = TRANSIT_FIRST_CUSTOM + 1;
-
-    /** Transition type for launching 2 tasks simultaneously. */
-    public static final int TRANSIT_SPLIT_SCREEN_PAIR_OPEN = TRANSIT_FIRST_CUSTOM + 2;
-
     /** Transition type for exiting PIP via the Shell, via pressing the expand button. */
-    public static final int TRANSIT_EXIT_PIP = TRANSIT_FIRST_CUSTOM + 3;
+    public static final int TRANSIT_EXIT_PIP = TRANSIT_FIRST_CUSTOM + 1;
+
+    public static final int TRANSIT_EXIT_PIP_TO_SPLIT =  TRANSIT_FIRST_CUSTOM + 2;
 
     /** Transition type for removing PIP via the Shell, either via Dismiss bubble or Close. */
-    public static final int TRANSIT_REMOVE_PIP = TRANSIT_FIRST_CUSTOM + 4;
+    public static final int TRANSIT_REMOVE_PIP = TRANSIT_FIRST_CUSTOM + 3;
+
+    /** Transition type for launching 2 tasks simultaneously. */
+    public static final int TRANSIT_SPLIT_SCREEN_PAIR_OPEN = TRANSIT_FIRST_CUSTOM + 4;
 
     /** Transition type for entering split by opening an app into side-stage. */
     public static final int TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE = TRANSIT_FIRST_CUSTOM + 5;
 
+    /** Transition type for dismissing split-screen via dragging the divider off the screen. */
+    public static final int TRANSIT_SPLIT_DISMISS_SNAP = TRANSIT_FIRST_CUSTOM + 6;
+
     /** Transition type for dismissing split-screen. */
-    public static final int TRANSIT_SPLIT_DISMISS = TRANSIT_FIRST_CUSTOM + 6;
+    public static final int TRANSIT_SPLIT_DISMISS = TRANSIT_FIRST_CUSTOM + 7;
 
     private final WindowOrganizer mOrganizer;
     private final Context mContext;
@@ -357,6 +359,28 @@
             return;
         }
 
+        // apply transfer starting window directly if there is no other task change.
+        final int changeSize = info.getChanges().size();
+        if (changeSize == 2) {
+            boolean nonTaskChange = true;
+            boolean transferStartingWindow = false;
+            for (int i = changeSize - 1; i >= 0; --i) {
+                final TransitionInfo.Change change = info.getChanges().get(i);
+                if (change.getTaskInfo() != null) {
+                    nonTaskChange = false;
+                    break;
+                }
+                if ((change.getFlags() & FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT) != 0) {
+                    transferStartingWindow = true;
+                }
+            }
+            if (nonTaskChange && transferStartingWindow) {
+                t.apply();
+                onFinish(transitionToken, null /* wct */, null /* wctCB */);
+                return;
+            }
+        }
+
         final ActiveTransition active = mActiveTransitions.get(activeIdx);
         active.mInfo = info;
         active.mStartT = t;
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt
index c4be785..68b0b4e 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt
@@ -17,11 +17,11 @@
 @file:JvmName("CommonAssertions")
 package com.android.wm.shell.flicker
 
-import android.graphics.Region
 import android.view.Surface
 import com.android.server.wm.flicker.FlickerTestParameter
 import com.android.server.wm.flicker.helpers.WindowUtils
 import com.android.server.wm.traces.common.FlickerComponentName
+import com.android.server.wm.traces.common.region.Region
 
 fun FlickerTestParameter.appPairsDividerIsVisibleAtEnd() {
     assertLayersEnd {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt
index d9b7277..ae92366 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt
@@ -82,7 +82,7 @@
     @Test
     override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
 
-    @Presubmit
+    @FlakyTest(bugId = 206753786)
     @Test
     override fun statusBarLayerRotatesScales() {
         // This test doesn't work in shell transitions because of b/206753786
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt
index 20a9475..f1b0135 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt
@@ -67,7 +67,7 @@
     @Test
     override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
 
-    @Presubmit
+    @FlakyTest(bugId = 206753786)
     @Test
     override fun statusBarLayerRotatesScales() {
         // This test doesn't work in shell transitions because of b/206753786
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestSupportPairNonResizeableApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestSupportPairNonResizeableApps.kt
index 2d47027..6998cd2 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestSupportPairNonResizeableApps.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestSupportPairNonResizeableApps.kt
@@ -86,7 +86,7 @@
     @Test
     override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
 
-    @Presubmit
+    @FlakyTest(bugId = 206753786)
     @Test
     override fun statusBarLayerRotatesScales() {
         // This test doesn't work in shell transitions because of b/206753786
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt
index 9b4506c..7a53224 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt
@@ -71,7 +71,7 @@
     @Test
     override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
 
-    @Presubmit
+    @FlakyTest(bugId = 206753786)
     @Test
     override fun statusBarLayerRotatesScales() {
         // This test doesn't work in shell transitions because of b/206753786
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt
index 10ccd6a..f2f4877 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt
@@ -18,6 +18,7 @@
 
 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
@@ -92,6 +93,10 @@
         testSpec.appPairsSecondaryBoundsIsVisibleAtEnd(testSpec.endRotation,
             secondaryApp.component)
 
+    @FlakyTest(bugId = 206753786)
+    @Test
+    override fun statusBarLayerRotatesScales() = super.statusBarLayerRotatesScales()
+
     companion object {
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt
index cf7343b..2a173d1 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt
@@ -18,6 +18,7 @@
 
 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
@@ -79,6 +80,10 @@
     @Test
     override fun statusBarLayerIsVisible() = super.statusBarLayerIsVisible()
 
+    @FlakyTest(bugId = 206753786)
+    @Test
+    override fun statusBarLayerRotatesScales() = super.statusBarLayerRotatesScales()
+
     @Presubmit
     @Test
     fun bothAppWindowsVisible() {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/AppPairsHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/AppPairsHelper.kt
index 623055f6..efae207 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/AppPairsHelper.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/AppPairsHelper.kt
@@ -17,23 +17,23 @@
 package com.android.wm.shell.flicker.helpers
 
 import android.app.Instrumentation
-import android.graphics.Region
 import com.android.server.wm.flicker.Flicker
 import com.android.server.wm.flicker.helpers.WindowUtils
 import com.android.server.wm.traces.common.FlickerComponentName
+import com.android.server.wm.traces.common.region.Region
 
 class AppPairsHelper(
     instrumentation: Instrumentation,
     activityLabel: String,
     component: FlickerComponentName
 ) : BaseAppHelper(instrumentation, activityLabel, component) {
-    fun getPrimaryBounds(dividerBounds: Region): android.graphics.Region {
+    fun getPrimaryBounds(dividerBounds: Region): Region {
         val primaryAppBounds = Region(0, 0, dividerBounds.bounds.right,
                 dividerBounds.bounds.bottom + WindowUtils.dockedStackDividerInset)
         return primaryAppBounds
     }
 
-    fun getSecondaryBounds(dividerBounds: Region): android.graphics.Region {
+    fun getSecondaryBounds(dividerBounds: Region): Region {
         val displayBounds = WindowUtils.displayBounds
         val secondaryAppBounds = Region(0,
                 dividerBounds.bounds.bottom - WindowUtils.dockedStackDividerInset,
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 2357b0d..8e6fa5f 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,7 +17,6 @@
 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
@@ -26,6 +25,7 @@
 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.common.Rect
 import com.android.server.wm.traces.parser.toFlickerComponent
 import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
 import com.android.wm.shell.flicker.pip.tv.closeTvPipWindow
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 77fb101..2c02d2c 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
@@ -110,7 +110,7 @@
     @Test
     fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales()
 
-    @Presubmit
+    @FlakyTest(bugId = 206753786)
     @Test
     fun statusBarLayerRotatesScales() {
         // This test doesn't work in shell transitions because of b/206753786
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 6041e23..7d7add4 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
@@ -16,7 +16,6 @@
 
 package com.android.wm.shell.flicker.legacysplitscreen
 
-import android.graphics.Region
 import android.util.Rational
 import android.view.Surface
 import androidx.test.filters.FlakyTest
@@ -41,6 +40,7 @@
 import com.android.server.wm.flicker.statusBarLayerIsVisible
 import com.android.server.wm.flicker.statusBarLayerRotatesScales
 import com.android.server.wm.flicker.statusBarWindowIsVisible
+import com.android.server.wm.traces.common.region.Region
 import com.android.server.wm.traces.parser.toFlickerComponent
 import com.android.wm.shell.flicker.DOCKED_STACK_DIVIDER_COMPONENT
 import com.android.wm.shell.flicker.helpers.SimpleAppHelper
@@ -135,6 +135,7 @@
     @Test
     fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales()
 
+    @FlakyTest(bugId = 206753786)
     @Test
     fun statusBarLayerRotatesScales() {
         // This test doesn't work in shell transitions because of b/206753786
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppAndEnterSplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppAndEnterSplitScreen.kt
index e44d7d6..5678899 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppAndEnterSplitScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppAndEnterSplitScreen.kt
@@ -77,7 +77,7 @@
     @Test
     fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales()
 
-    @Presubmit
+    @FlakyTest(bugId = 206753786)
     @Test
     fun statusBarLayerRotatesScales() {
         // This test doesn't work in shell transitions because of b/206753786
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppInSplitScreenMode.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppInSplitScreenMode.kt
index d33d92b..c2edf9d 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppInSplitScreenMode.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppInSplitScreenMode.kt
@@ -76,7 +76,7 @@
     @Test
     fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales()
 
-    @Presubmit
+    @FlakyTest(bugId = 206753786)
     @Test
     fun statusBarLayerRotatesScales() {
         // This test doesn't work in shell transitions because of b/206753786
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppAndEnterSplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppAndEnterSplitScreen.kt
index ece68df..777998c 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppAndEnterSplitScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppAndEnterSplitScreen.kt
@@ -18,6 +18,7 @@
 
 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
@@ -85,7 +86,7 @@
     @Test
     fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales()
 
-    @Presubmit
+    @FlakyTest(bugId = 206753786)
     @Test
     fun statusBarLayerRotatesScales() {
         // This test doesn't work in shell transitions because of b/206753786
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppInSplitScreenMode.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppInSplitScreenMode.kt
index 127301f..914b11d 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppInSplitScreenMode.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppInSplitScreenMode.kt
@@ -91,7 +91,7 @@
     @Test
     fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales()
 
-    @Presubmit
+    @FlakyTest(bugId = 206753786)
     @Test
     fun statusBarLayerRotatesScales() {
         // This test doesn't work in shell transitions because of b/206753786
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 f3a3db1..d3bb008 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
@@ -91,7 +91,7 @@
     }
 
     /** {@inheritDoc}  */
-    @Presubmit
+    @FlakyTest(bugId = 206753786)
     @Test
     override fun statusBarLayerRotatesScales() {
         // This test doesn't work in shell transitions because of b/206753786
@@ -128,8 +128,8 @@
     @Presubmit
     @Test
     fun pipWindowRemainInsideVisibleBounds() {
-        testSpec.assertWm {
-            coversAtMost(displayBounds, pipApp.component)
+        testSpec.assertWmVisibleRegion(pipApp.component) {
+            coversAtMost(displayBounds)
         }
     }
 
@@ -140,8 +140,8 @@
     @Presubmit
     @Test
     fun pipLayerRemainInsideVisibleBounds() {
-        testSpec.assertLayers {
-            coversAtMost(displayBounds, pipApp.component)
+        testSpec.assertLayersVisibleRegion(pipApp.component) {
+            coversAtMost(displayBounds)
         }
     }
 
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 f923a23..fa9fbcd 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
@@ -119,7 +119,7 @@
      * Checks that the [FlickerComponentName.STATUS_BAR] has the correct position at
      * the start and end of the transition
      */
-    @Presubmit
+    @FlakyTest(bugId = 206753786)
     @Test
     override fun statusBarLayerRotatesScales() {
         // This test doesn't work in shell transitions because of b/206753786
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
index 3e7e2f5..f8a3aff 100644
--- 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
@@ -45,8 +45,8 @@
     @Presubmit
     @Test
     open fun pipAppWindowRemainInsideVisibleBounds() {
-        testSpec.assertWm {
-            coversAtMost(displayBounds, pipApp.component)
+        testSpec.assertWmVisibleRegion(pipApp.component) {
+            coversAtMost(displayBounds)
         }
     }
 
@@ -57,8 +57,8 @@
     @Presubmit
     @Test
     open fun pipAppLayerRemainInsideVisibleBounds() {
-        testSpec.assertLayers {
-            coversAtMost(displayBounds, pipApp.component)
+        testSpec.assertLayersVisibleRegion(pipApp.component) {
+            coversAtMost(displayBounds)
         }
     }
 
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
index 4d63d14..2231d88 100644
--- 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
@@ -16,8 +16,8 @@
 
 package com.android.wm.shell.flicker.pip
 
-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
@@ -80,7 +80,7 @@
         }
 
     /** {@inheritDoc}  */
-    @Presubmit
+    @FlakyTest(bugId = 206753786)
     @Test
     override fun statusBarLayerRotatesScales() {
         // This test doesn't work in shell transitions because of b/206753786
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
index 19d8671..fcac2c7 100644
--- 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
@@ -16,7 +16,6 @@
 
 package com.android.wm.shell.flicker.pip
 
-import android.platform.test.annotations.Presubmit
 import android.view.Surface
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
@@ -100,7 +99,7 @@
     }
 
     /** {@inheritDoc}  */
-    @Presubmit
+    @FlakyTest(bugId = 206753786)
     @Test
     override fun statusBarLayerRotatesScales() {
         // This test doesn't work in shell transitions because of b/206753786
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
index 338687f..c75076d 100644
--- 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
@@ -16,7 +16,6 @@
 
 package com.android.wm.shell.flicker.pip
 
-import android.platform.test.annotations.Presubmit
 import android.view.Surface
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
@@ -96,7 +95,7 @@
     }
 
     /** {@inheritDoc}  */
-    @Presubmit
+    @FlakyTest(bugId = 206753786)
     @Test
     override fun statusBarLayerRotatesScales() {
         // This test doesn't work in shell transitions because of b/206753786
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithSwipeDownTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithSwipeDownTest.kt
index 40be21a..8e6603b 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithSwipeDownTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithSwipeDownTest.kt
@@ -16,7 +16,6 @@
 
 package com.android.wm.shell.flicker.pip
 
-import android.platform.test.annotations.Presubmit
 import android.view.Surface
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
@@ -80,7 +79,7 @@
     @Test
     override fun pipLayerBecomesInvisible() = super.pipLayerBecomesInvisible()
 
-    @Presubmit
+    @FlakyTest(bugId = 206753786)
     @Test
     override fun statusBarLayerRotatesScales() {
         // This test doesn't work in shell transitions because of b/206753786
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
index 3511cc2..52177c2 100644
--- 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
@@ -78,8 +78,8 @@
     @Presubmit
     @Test
     fun pipWindowRemainInsideVisibleBounds() {
-        testSpec.assertWm {
-            coversAtMost(displayBounds, pipApp.component)
+        testSpec.assertWmVisibleRegion(pipApp.component) {
+            coversAtMost(displayBounds)
         }
     }
 
@@ -90,8 +90,8 @@
     @Presubmit
     @Test
     fun pipLayerRemainInsideVisibleBounds() {
-        testSpec.assertLayers {
-            coversAtMost(displayBounds, pipApp.component)
+        testSpec.assertLayersVisibleRegion(pipApp.component) {
+            coversAtMost(displayBounds)
         }
     }
 
@@ -165,6 +165,10 @@
         }
     }
 
+    @FlakyTest(bugId = 206753786)
+    @Test
+    override fun statusBarLayerRotatesScales() = super.statusBarLayerRotatesScales()
+
     companion object {
         /**
          * Creates the test configurations.
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
index 10a542f..f9e180e 100644
--- 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
@@ -16,8 +16,8 @@
 
 package com.android.wm.shell.flicker.pip
 
-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
@@ -25,8 +25,8 @@
 import com.android.server.wm.flicker.annotation.Group3
 import com.android.server.wm.flicker.dsl.FlickerBuilder
 import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
-import com.android.server.wm.flicker.traces.RegionSubject
 import org.junit.Assume.assumeFalse
+import com.android.server.wm.flicker.traces.region.RegionSubject
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -83,7 +83,7 @@
     }
 
     /** {@inheritDoc}  */
-    @Presubmit
+    @FlakyTest(bugId = 206753786)
     @Test
     override fun statusBarLayerRotatesScales() {
         // This test doesn't work in shell transitions because of b/206753786
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
index 6e0324c..0499e7d 100644
--- 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
@@ -19,7 +19,7 @@
 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.flicker.traces.region.RegionSubject
 import com.android.wm.shell.flicker.helpers.FixedAppHelper
 import org.junit.Test
 
@@ -66,8 +66,8 @@
     @Presubmit
     @Test
     open fun pipWindowRemainInsideVisibleBounds() {
-        testSpec.assertWm {
-            coversAtMost(displayBounds, pipApp.component)
+        testSpec.assertWmVisibleRegion(pipApp.component) {
+            coversAtMost(displayBounds)
         }
     }
 
@@ -78,8 +78,8 @@
     @Presubmit
     @Test
     open fun pipLayerRemainInsideVisibleBounds() {
-        testSpec.assertLayers {
-            coversAtMost(displayBounds, pipApp.component)
+        testSpec.assertLayersVisibleRegion(pipApp.component) {
+            coversAtMost(displayBounds)
         }
     }
 
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
index cb6ba0e6..b7bfa1b 100644
--- 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
@@ -16,16 +16,16 @@
 
 package com.android.wm.shell.flicker.pip
 
-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.annotation.Group3
 import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.traces.region.RegionSubject
 import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
-import com.android.server.wm.flicker.traces.RegionSubject
 import org.junit.Assume.assumeFalse
 import org.junit.FixMethodOrder
 import org.junit.Test
@@ -83,7 +83,7 @@
     }
 
     /** {@inheritDoc}  */
-    @Presubmit
+    @FlakyTest(bugId = 206753786)
     @Test
     override fun statusBarLayerRotatesScales() {
         // This test doesn't work in shell transitions because of b/206753786
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 81ac10f..c36dfda 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
@@ -18,6 +18,7 @@
 
 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
@@ -73,7 +74,7 @@
         }
 
     /** {@inheritDoc}  */
-    @Presubmit
+    @FlakyTest(bugId = 206753786)
     @Test
     override fun statusBarLayerRotatesScales() {
         // This test doesn't work in shell transitions because of b/206753786
@@ -87,9 +88,9 @@
     @Presubmit
     @Test
     fun pipInVisibleBounds() {
-        testSpec.assertWm {
+        testSpec.assertWmVisibleRegion(pipApp.component) {
             val displayBounds = WindowUtils.getDisplayBounds(testSpec.startRotation)
-            coversAtMost(displayBounds, pipApp.component)
+            coversAtMost(displayBounds)
         }
     }
 
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 70075dd..df58194 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
@@ -90,7 +90,7 @@
         }
 
     /** {@inheritDoc}  */
-    @Presubmit
+    @FlakyTest(bugId = 206753786)
     @Test
     override fun statusBarLayerRotatesScales() {
         // This test doesn't work in shell transitions because of b/206753786
@@ -101,8 +101,8 @@
     @FlakyTest(bugId = 161435597)
     @Test
     fun pipWindowInsideDisplayBounds() {
-        testSpec.assertWm {
-            coversAtMost(displayBounds, pipApp.component)
+        testSpec.assertWmVisibleRegion(pipApp.component) {
+            coversAtMost(displayBounds)
         }
     }
 
@@ -119,8 +119,8 @@
     @FlakyTest(bugId = 161435597)
     @Test
     fun pipLayerInsideDisplayBounds() {
-        testSpec.assertLayers {
-            coversAtMost(displayBounds, pipApp.component)
+        testSpec.assertLayersVisibleRegion(pipApp.component) {
+            coversAtMost(displayBounds)
         }
     }
 
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 59bbdfe..b2b50ad 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
@@ -27,12 +27,10 @@
 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.helpers.isShellTransitionsEnabled
 import com.android.server.wm.flicker.helpers.setRotation
 import com.android.server.wm.flicker.navBarLayerRotatesAndScales
 import com.android.server.wm.flicker.statusBarLayerRotatesScales
 import com.android.wm.shell.flicker.helpers.FixedAppHelper
-import org.junit.Assume.assumeFalse
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -100,7 +98,7 @@
     /**
      * Checks the position of the status bar at the start and end of the transition
      */
-    @Presubmit
+    @FlakyTest(bugId = 206753786)
     @Test
     override fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales()
 
@@ -121,8 +119,6 @@
     @Presubmit
     @Test
     fun appLayerRotates_EndingBounds() {
-        // This CUJ don't work in shell transitions because of b/204570898 b/204562589 b/206753786
-        assumeFalse(isShellTransitionsEnabled)
         testSpec.assertLayersEnd {
             visibleRegion(fixedApp.component).coversExactly(screenBoundsEnd)
         }
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 3121218..dbd3d8c 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
@@ -115,7 +115,7 @@
         super.navBarLayerRotatesAndScales()
     }
 
-    @Presubmit
+    @FlakyTest(bugId = 206753786)
     @Test
     override fun statusBarLayerRotatesScales() {
         // This test doesn't work in shell transitions because of b/206753786
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
index 0a3a849..16bc5075 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
@@ -109,6 +109,7 @@
         mSpiedTransitionState = spy(new OneHandedState());
 
         when(mMockDisplayController.getDisplay(anyInt())).thenReturn(mDisplay);
+        when(mMockDisplayController.getDisplayLayout(anyInt())).thenReturn(null);
         when(mMockDisplayAreaOrganizer.getDisplayAreaTokenMap()).thenReturn(new ArrayMap<>());
         when(mMockDisplayAreaOrganizer.isReady()).thenReturn(true);
         when(mMockBackgroundOrganizer.isRegistered()).thenReturn(true);
@@ -153,6 +154,13 @@
     }
 
     @Test
+    public void testNullDisplayLayout() {
+        mSpiedOneHandedController.updateDisplayLayout(0);
+
+        verify(mMockDisplayAreaOrganizer, never()).setDisplayLayout(any());
+    }
+
+    @Test
     public void testStartOneHandedShouldTriggerScheduleOffset() {
         mSpiedTransitionState.setState(STATE_NONE);
         mSpiedOneHandedController.setOneHandedEnabled(true);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizerTest.java
index ef16fd3..1d92a48 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizerTest.java
@@ -432,4 +432,11 @@
 
         assertThat(testSpiedDisplayAreaOrganizer.isReady()).isFalse();
     }
+
+    @Test
+    public void testDisplayArea_setDisplayLayout_should_updateDisplayBounds() {
+        mSpiedDisplayAreaOrganizer.setDisplayLayout(mDisplayLayout);
+
+        verify(mSpiedDisplayAreaOrganizer).updateDisplayBounds();
+    }
 }
diff --git a/libs/hwui/Outline.h b/libs/hwui/Outline.h
index 2eb2c7c..e16fd8c 100644
--- a/libs/hwui/Outline.h
+++ b/libs/hwui/Outline.h
@@ -88,14 +88,10 @@
 
     bool getShouldClip() const { return mShouldClip; }
 
-    bool willClip() const {
-        // only round rect outlines can be used for clipping
-        return mShouldClip && (mType == Type::RoundRect);
-    }
+    bool willClip() const { return mShouldClip; }
 
-    bool willRoundRectClip() const {
-        // only round rect outlines can be used for clipping
-        return willClip() && MathUtils::isPositive(mRadius);
+    bool willComplexClip() const {
+        return mShouldClip && (mType != Type::RoundRect || MathUtils::isPositive(mRadius));
     }
 
     bool getAsRoundRect(Rect* outRect, float* outRadius) const {
diff --git a/libs/hwui/ProfileData.cpp b/libs/hwui/ProfileData.cpp
index dd84396..3d0ca0a 100644
--- a/libs/hwui/ProfileData.cpp
+++ b/libs/hwui/ProfileData.cpp
@@ -137,6 +137,7 @@
     histogramGPUForEach([fd](HistogramEntry entry) {
         dprintf(fd, " %ums=%u", entry.renderTimeMs, entry.frameCount);
     });
+    dprintf(fd, "\n");
 }
 
 uint32_t ProfileData::findPercentile(int percentile) const {
diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h
index cd622eb..064ba7a 100644
--- a/libs/hwui/RenderProperties.h
+++ b/libs/hwui/RenderProperties.h
@@ -165,11 +165,11 @@
     bool prepareForFunctorPresence(bool willHaveFunctor, bool ancestorDictatesFunctorsNeedLayer) {
         // parent may have already dictated that a descendant layer is needed
         bool functorsNeedLayer =
-                ancestorDictatesFunctorsNeedLayer
-                || CC_UNLIKELY(isClipMayBeComplex())
+                ancestorDictatesFunctorsNeedLayer ||
+                CC_UNLIKELY(isClipMayBeComplex())
 
                 // Round rect clipping forces layer for functors
-                || CC_UNLIKELY(getOutline().willRoundRectClip()) ||
+                || CC_UNLIKELY(getOutline().willComplexClip()) ||
                 CC_UNLIKELY(getRevealClip().willClip())
 
                 // Complex matrices forces layer, due to stencil clipping
diff --git a/libs/hwui/jni/RenderEffect.cpp b/libs/hwui/jni/RenderEffect.cpp
index a48d7f7..213f35a 100644
--- a/libs/hwui/jni/RenderEffect.cpp
+++ b/libs/hwui/jni/RenderEffect.cpp
@@ -127,6 +127,32 @@
     return reinterpret_cast<jlong>(shaderFilter.release());
 }
 
+static inline int ThrowIAEFmt(JNIEnv* env, const char* fmt, ...) {
+    va_list args;
+    va_start(args, fmt);
+    int ret = jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", fmt, args);
+    va_end(args);
+    return ret;
+}
+
+static jlong createRuntimeShaderEffect(JNIEnv* env, jobject, jlong shaderBuilderHandle,
+                                       jstring inputShaderName) {
+    SkRuntimeShaderBuilder* builder =
+            reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilderHandle);
+    ScopedUtfChars name(env, inputShaderName);
+
+    if (builder->child(name.c_str()).fChild == nullptr) {
+        ThrowIAEFmt(env,
+                    "unable to find a uniform with the name '%s' of the correct "
+                    "type defined by the provided RuntimeShader",
+                    name.c_str());
+        return 0;
+    }
+
+    sk_sp<SkImageFilter> filter = SkImageFilters::RuntimeShader(*builder, name.c_str(), nullptr);
+    return reinterpret_cast<jlong>(filter.release());
+}
+
 static void RenderEffect_safeUnref(SkImageFilter* filter) {
     SkSafeUnref(filter);
 }
@@ -136,15 +162,16 @@
 }
 
 static const JNINativeMethod gRenderEffectMethods[] = {
-    {"nativeGetFinalizer", "()J", (void*)getRenderEffectFinalizer},
-    {"nativeCreateOffsetEffect", "(FFJ)J", (void*)createOffsetEffect},
-    {"nativeCreateBlurEffect", "(FFJI)J", (void*)createBlurEffect},
-    {"nativeCreateBitmapEffect", "(JFFFFFFFF)J", (void*)createBitmapEffect},
-    {"nativeCreateColorFilterEffect", "(JJ)J", (void*)createColorFilterEffect},
-    {"nativeCreateBlendModeEffect", "(JJI)J", (void*)createBlendModeEffect},
-    {"nativeCreateChainEffect", "(JJ)J", (void*)createChainEffect},
-    {"nativeCreateShaderEffect", "(J)J", (void*)createShaderEffect}
-};
+        {"nativeGetFinalizer", "()J", (void*)getRenderEffectFinalizer},
+        {"nativeCreateOffsetEffect", "(FFJ)J", (void*)createOffsetEffect},
+        {"nativeCreateBlurEffect", "(FFJI)J", (void*)createBlurEffect},
+        {"nativeCreateBitmapEffect", "(JFFFFFFFF)J", (void*)createBitmapEffect},
+        {"nativeCreateColorFilterEffect", "(JJ)J", (void*)createColorFilterEffect},
+        {"nativeCreateBlendModeEffect", "(JJI)J", (void*)createBlendModeEffect},
+        {"nativeCreateChainEffect", "(JJ)J", (void*)createChainEffect},
+        {"nativeCreateShaderEffect", "(J)J", (void*)createShaderEffect},
+        {"nativeCreateRuntimeShaderEffect", "(JLjava/lang/String;)J",
+         (void*)createRuntimeShaderEffect}};
 
 int register_android_graphics_RenderEffect(JNIEnv* env) {
     android::RegisterMethodsOrDie(env, "android/graphics/RenderEffect",
diff --git a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
index bd93a4f..27865b3 100644
--- a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
+++ b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
@@ -609,10 +609,19 @@
         LOG_ALWAYS_FATAL_IF(env->GetJavaVM(&vm) != JNI_OK, "Unable to get Java VM");
         auto globalCallbackRef = std::make_shared<JGlobalRefHolder>(vm,
                 env->NewGlobalRef(frameCallback));
-        proxy->setFrameCallback([globalCallbackRef](int64_t frameNr) {
+        proxy->setFrameCallback([globalCallbackRef](int32_t syncResult,
+                                                    int64_t frameNr) -> std::function<void(bool)> {
             JNIEnv* env = getenv(globalCallbackRef->vm());
-            env->CallVoidMethod(globalCallbackRef->object(), gFrameDrawingCallback.onFrameDraw,
-                    static_cast<jlong>(frameNr));
+            ScopedLocalRef<jobject> frameCommitCallback(
+                    env, env->CallObjectMethod(
+                                 globalCallbackRef->object(), gFrameDrawingCallback.onFrameDraw,
+                                 static_cast<jint>(syncResult), static_cast<jlong>(frameNr)));
+            if (frameCommitCallback == nullptr) {
+                return nullptr;
+            }
+            sp<FrameCommitWrapper> wrapper =
+                    sp<FrameCommitWrapper>::make(env, frameCommitCallback.get());
+            return [wrapper](bool didProduceBuffer) { wrapper->onFrameCommit(didProduceBuffer); };
         });
     }
 }
@@ -623,7 +632,7 @@
     if (!callback) {
         proxy->setFrameCommitCallback(nullptr);
     } else {
-        sp<FrameCommitWrapper> wrapper = new FrameCommitWrapper{env, callback};
+        sp<FrameCommitWrapper> wrapper = sp<FrameCommitWrapper>::make(env, callback);
         proxy->setFrameCommitCallback(
                 [wrapper](bool didProduceBuffer) { wrapper->onFrameCommit(didProduceBuffer); });
     }
@@ -1003,8 +1012,9 @@
 
     jclass frameCallbackClass = FindClassOrDie(env,
             "android/graphics/HardwareRenderer$FrameDrawingCallback");
-    gFrameDrawingCallback.onFrameDraw = GetMethodIDOrDie(env, frameCallbackClass,
-            "onFrameDraw", "(J)V");
+    gFrameDrawingCallback.onFrameDraw =
+            GetMethodIDOrDie(env, frameCallbackClass, "onFrameDraw",
+                             "(IJ)Landroid/graphics/HardwareRenderer$FrameCommitCallback;");
 
     jclass frameCommitClass =
             FindClassOrDie(env, "android/graphics/HardwareRenderer$FrameCommitCallback");
diff --git a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
index 48145d2..507d3dc 100644
--- a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
+++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
@@ -88,6 +88,10 @@
         if (pendingClip) {
             canvas->clipRect(*pendingClip);
         }
+        const SkPath* path = outline.getPath();
+        if (path) {
+            canvas->clipPath(*path, SkClipOp::kIntersect, true);
+        }
         return;
     }
 
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index 94aedd0..8c98c72 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -158,7 +158,8 @@
 
     // Grab a copy of everything we need
     CanvasContext* context = mContext;
-    std::function<void(int64_t)> frameCallback = std::move(mFrameCallback);
+    std::function<std::function<void(bool)>(int32_t, int64_t)> frameCallback =
+            std::move(mFrameCallback);
     std::function<void()> frameCompleteCallback = std::move(mFrameCompleteCallback);
     mFrameCallback = nullptr;
     mFrameCompleteCallback = nullptr;
@@ -173,8 +174,13 @@
 
     // Even if we aren't drawing this vsync pulse the next frame number will still be accurate
     if (CC_UNLIKELY(frameCallback)) {
-        context->enqueueFrameWork(
-                [frameCallback, frameNr = context->getFrameNumber()]() { frameCallback(frameNr); });
+        context->enqueueFrameWork([frameCallback, context, syncResult = mSyncResult,
+                                   frameNr = context->getFrameNumber()]() {
+            auto frameCommitCallback = std::move(frameCallback(syncResult, frameNr));
+            if (frameCommitCallback) {
+                context->addFrameCommitListener(std::move(frameCommitCallback));
+            }
+        });
     }
 
     nsecs_t dequeueBufferDuration = 0;
diff --git a/libs/hwui/renderthread/DrawFrameTask.h b/libs/hwui/renderthread/DrawFrameTask.h
index e3ea802..8ad8abc 100644
--- a/libs/hwui/renderthread/DrawFrameTask.h
+++ b/libs/hwui/renderthread/DrawFrameTask.h
@@ -77,7 +77,7 @@
 
     void run();
 
-    void setFrameCallback(std::function<void(int64_t)>&& callback) {
+    void setFrameCallback(std::function<std::function<void(bool)>(int32_t, int64_t)>&& callback) {
         mFrameCallback = std::move(callback);
     }
 
@@ -126,7 +126,7 @@
 
     int64_t mFrameInfo[UI_THREAD_FRAME_INFO_SIZE];
 
-    std::function<void(int64_t)> mFrameCallback;
+    std::function<std::function<void(bool)>(int32_t, int64_t)> mFrameCallback;
     std::function<void(bool)> mFrameCommitCallback;
     std::function<void()> mFrameCompleteCallback;
 
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 430c4d3..026699c 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -327,7 +327,8 @@
             [this, cb = callback]() { mContext->setPrepareSurfaceControlForWebviewCallback(cb); });
 }
 
-void RenderProxy::setFrameCallback(std::function<void(int64_t)>&& callback) {
+void RenderProxy::setFrameCallback(
+        std::function<std::function<void(bool)>(int32_t, int64_t)>&& callback) {
     mDrawFrameTask.setFrameCallback(std::move(callback));
 }
 
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index 6d46be4..491dbd7 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -124,7 +124,7 @@
     void setASurfaceTransactionCallback(
             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 setFrameCallback(std::function<std::function<void(bool)>(int32_t, int64_t)>&& callback);
     void setFrameCommitCallback(std::function<void(bool)>&& callback);
     void setFrameCompleteCallback(std::function<void()>&& callback);
 
diff --git a/libs/hwui/tests/common/scenes/PathClippingAnimation.cpp b/libs/hwui/tests/common/scenes/PathClippingAnimation.cpp
new file mode 100644
index 0000000..1e343c1
--- /dev/null
+++ b/libs/hwui/tests/common/scenes/PathClippingAnimation.cpp
@@ -0,0 +1,153 @@
+/*
+ * 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.
+ */
+
+#include <vector>
+
+#include "TestSceneBase.h"
+
+class PathClippingAnimation : public TestScene {
+public:
+    int mSpacing, mSize;
+    bool mClip, mAnimateClip;
+    int mMaxCards;
+    std::vector<sp<RenderNode> > cards;
+
+    PathClippingAnimation(int spacing, int size, bool clip, bool animateClip, int maxCards)
+            : mSpacing(spacing)
+            , mSize(size)
+            , mClip(clip)
+            , mAnimateClip(animateClip)
+            , mMaxCards(maxCards) {}
+
+    PathClippingAnimation(int spacing, int size, bool clip, bool animateClip)
+            : PathClippingAnimation(spacing, size, clip, animateClip, INT_MAX) {}
+
+    void createContent(int width, int height, Canvas& canvas) override {
+        canvas.drawColor(0xFFFFFFFF, SkBlendMode::kSrcOver);
+        canvas.enableZ(true);
+        int ci = 0;
+        int numCards = 0;
+
+        for (int x = 0; x < width; x += mSpacing) {
+            for (int y = 0; y < height; y += mSpacing) {
+                auto color = BrightColors[ci++ % BrightColorsCount];
+                auto card = TestUtils::createNode(
+                        x, y, x + mSize, y + mSize, [&](RenderProperties& props, Canvas& canvas) {
+                            canvas.drawColor(color, SkBlendMode::kSrcOver);
+                            if (mClip) {
+                                // Create circular path that rounds around the inside of all
+                                // four corners of the given square defined by mSize*mSize
+                                SkPath path = setPath(mSize);
+                                props.mutableOutline().setPath(&path, 1);
+                                props.mutableOutline().setShouldClip(true);
+                            }
+                        });
+                canvas.drawRenderNode(card.get());
+                cards.push_back(card);
+                ++numCards;
+                if (numCards >= mMaxCards) {
+                    break;
+                }
+            }
+            if (numCards >= mMaxCards) {
+                break;
+            }
+        }
+
+        canvas.enableZ(false);
+    }
+
+    SkPath setPath(int size) {
+        SkPath path;
+        path.moveTo(0, size / 2);
+        path.cubicTo(0, size * .75, size * .25, size, size / 2, size);
+        path.cubicTo(size * .75, size, size, size * .75, size, size / 2);
+        path.cubicTo(size, size * .25, size * .75, 0, size / 2, 0);
+        path.cubicTo(size / 4, 0, 0, size / 4, 0, size / 2);
+        return path;
+    }
+
+    void doFrame(int frameNr) override {
+        int curFrame = frameNr % 50;
+        if (curFrame > 25) curFrame = 50 - curFrame;
+        for (auto& card : cards) {
+            if (mAnimateClip) {
+                SkPath path = setPath(mSize - curFrame);
+                card->mutateStagingProperties().mutableOutline().setPath(&path, 1);
+            }
+            card->mutateStagingProperties().setTranslationX(curFrame);
+            card->mutateStagingProperties().setTranslationY(curFrame);
+            card->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y | RenderNode::DISPLAY_LIST);
+        }
+    }
+};
+
+static TestScene::Registrar _PathClippingUnclipped(TestScene::Info{
+        "pathClipping-unclipped", "Multiple RenderNodes, unclipped.",
+        [](const TestScene::Options&) -> test::TestScene* {
+            return new PathClippingAnimation(dp(100), dp(80), false, false);
+        }});
+
+static TestScene::Registrar _PathClippingUnclippedSingle(TestScene::Info{
+        "pathClipping-unclippedsingle", "A single RenderNode, unclipped.",
+        [](const TestScene::Options&) -> test::TestScene* {
+            return new PathClippingAnimation(dp(100), dp(80), false, false, 1);
+        }});
+
+static TestScene::Registrar _PathClippingUnclippedSingleLarge(TestScene::Info{
+        "pathClipping-unclippedsinglelarge", "A single large RenderNode, unclipped.",
+        [](const TestScene::Options&) -> test::TestScene* {
+            return new PathClippingAnimation(dp(100), dp(350), false, false, 1);
+        }});
+
+static TestScene::Registrar _PathClippingClipped80(TestScene::Info{
+        "pathClipping-clipped80", "Multiple RenderNodes, clipped by paths.",
+        [](const TestScene::Options&) -> test::TestScene* {
+            return new PathClippingAnimation(dp(100), dp(80), true, false);
+        }});
+
+static TestScene::Registrar _PathClippingClippedSingle(TestScene::Info{
+        "pathClipping-clippedsingle", "A single RenderNode, clipped by a path.",
+        [](const TestScene::Options&) -> test::TestScene* {
+            return new PathClippingAnimation(dp(100), dp(80), true, false, 1);
+        }});
+
+static TestScene::Registrar _PathClippingClippedSingleLarge(TestScene::Info{
+        "pathClipping-clippedsinglelarge", "A single large RenderNode, clipped by a path.",
+        [](const TestScene::Options&) -> test::TestScene* {
+            return new PathClippingAnimation(dp(100), dp(350), true, false, 1);
+        }});
+
+static TestScene::Registrar _PathClippingAnimated(TestScene::Info{
+        "pathClipping-animated",
+        "Multiple RenderNodes, clipped by paths which are being altered every frame.",
+        [](const TestScene::Options&) -> test::TestScene* {
+            return new PathClippingAnimation(dp(100), dp(80), true, true);
+        }});
+
+static TestScene::Registrar _PathClippingAnimatedSingle(TestScene::Info{
+        "pathClipping-animatedsingle",
+        "A single RenderNode, clipped by a path which is being altered every frame.",
+        [](const TestScene::Options&) -> test::TestScene* {
+            return new PathClippingAnimation(dp(100), dp(80), true, true, 1);
+        }});
+
+static TestScene::Registrar _PathClippingAnimatedSingleLarge(TestScene::Info{
+        "pathClipping-animatedsinglelarge",
+        "A single large RenderNode, clipped by a path which is being altered every frame.",
+        [](const TestScene::Options&) -> test::TestScene* {
+            return new PathClippingAnimation(dp(100), dp(350), true, true, 1);
+        }});
diff --git a/libs/hwui/tests/common/scenes/RoundRectClippingAnimation.cpp b/libs/hwui/tests/common/scenes/RoundRectClippingAnimation.cpp
index 163745b..e9f353d 100644
--- a/libs/hwui/tests/common/scenes/RoundRectClippingAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/RoundRectClippingAnimation.cpp
@@ -21,14 +21,17 @@
 class RoundRectClippingAnimation : public TestScene {
 public:
     int mSpacing, mSize;
+    int mMaxCards;
 
-    RoundRectClippingAnimation(int spacing, int size) : mSpacing(spacing), mSize(size) {}
+    RoundRectClippingAnimation(int spacing, int size, int maxCards = INT_MAX)
+            : mSpacing(spacing), mSize(size), mMaxCards(maxCards) {}
 
     std::vector<sp<RenderNode> > cards;
     void createContent(int width, int height, Canvas& canvas) override {
         canvas.drawColor(0xFFFFFFFF, SkBlendMode::kSrcOver);
         canvas.enableZ(true);
         int ci = 0;
+        int numCards = 0;
 
         for (int x = 0; x < width; x += mSpacing) {
             for (int y = 0; y < height; y += mSpacing) {
@@ -42,6 +45,13 @@
                         });
                 canvas.drawRenderNode(card.get());
                 cards.push_back(card);
+                ++numCards;
+                if (numCards >= mMaxCards) {
+                    break;
+                }
+            }
+            if (numCards >= mMaxCards) {
+                break;
             }
         }
 
@@ -71,3 +81,22 @@
         [](const TestScene::Options&) -> test::TestScene* {
             return new RoundRectClippingAnimation(dp(20), dp(20));
         }});
+
+static TestScene::Registrar _RoundRectClippingGrid(TestScene::Info{
+        "roundRectClipping-grid", "A grid of RenderNodes with round rect clipping outlines.",
+        [](const TestScene::Options&) -> test::TestScene* {
+            return new RoundRectClippingAnimation(dp(100), dp(80));
+        }});
+
+static TestScene::Registrar _RoundRectClippingSingle(TestScene::Info{
+        "roundRectClipping-single", "A single RenderNodes with round rect clipping outline.",
+        [](const TestScene::Options&) -> test::TestScene* {
+            return new RoundRectClippingAnimation(dp(100), dp(80), 1);
+        }});
+
+static TestScene::Registrar _RoundRectClippingSingleLarge(TestScene::Info{
+        "roundRectClipping-singlelarge",
+        "A single large RenderNodes with round rect clipping outline.",
+        [](const TestScene::Options&) -> test::TestScene* {
+            return new RoundRectClippingAnimation(dp(100), dp(350), 1);
+        }});
diff --git a/location/java/android/location/GnssMeasurementRequest.java b/location/java/android/location/GnssMeasurementRequest.java
index f509252..71cb0e3 100644
--- a/location/java/android/location/GnssMeasurementRequest.java
+++ b/location/java/android/location/GnssMeasurementRequest.java
@@ -16,10 +16,14 @@
 
 package android.location;
 
+import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.util.TimeUtils;
+
+import com.android.internal.util.Preconditions;
 
 import java.util.Objects;
 
@@ -29,13 +33,16 @@
 public final class GnssMeasurementRequest implements Parcelable {
     private final boolean mCorrelationVectorOutputsEnabled;
     private final boolean mFullTracking;
+    private final int mIntervalMillis;
 
     /**
      * Creates a {@link GnssMeasurementRequest} with a full list of parameters.
      */
-    private GnssMeasurementRequest(boolean fullTracking, boolean correlationVectorOutputsEnabled) {
+    private GnssMeasurementRequest(boolean fullTracking, boolean correlationVectorOutputsEnabled,
+            int intervalMillis) {
         mFullTracking = fullTracking;
         mCorrelationVectorOutputsEnabled = correlationVectorOutputsEnabled;
+        mIntervalMillis = intervalMillis;
     }
 
     /**
@@ -68,13 +75,26 @@
         return mFullTracking;
     }
 
+    /**
+     * Represents the requested time interval between the reported measurements in milliseconds.
+     *
+     * <p>If the time interval is not set, the default value is 0, which means the fastest rate the
+     * GNSS chipset can report.
+     *
+     * <p>The GNSS chipset may report measurements with a rate faster than requested.
+     */
+    public @IntRange(from = 0) int getIntervalMillis() {
+        return mIntervalMillis;
+    }
+
     @NonNull
     public static final Creator<GnssMeasurementRequest> CREATOR =
             new Creator<GnssMeasurementRequest>() {
                 @Override
                 @NonNull
                 public GnssMeasurementRequest createFromParcel(@NonNull Parcel parcel) {
-                    return new GnssMeasurementRequest(parcel.readBoolean(), parcel.readBoolean());
+                    return new GnssMeasurementRequest(parcel.readBoolean(), parcel.readBoolean(),
+                            parcel.readInt());
                 }
 
                 @Override
@@ -87,6 +107,7 @@
     public void writeToParcel(@NonNull Parcel parcel, int flags) {
         parcel.writeBoolean(mFullTracking);
         parcel.writeBoolean(mCorrelationVectorOutputsEnabled);
+        parcel.writeInt(mIntervalMillis);
     }
 
     @NonNull
@@ -94,11 +115,13 @@
     public String toString() {
         StringBuilder s = new StringBuilder();
         s.append("GnssMeasurementRequest[");
+        s.append("@");
+        TimeUtils.formatDuration(mIntervalMillis, s);
         if (mFullTracking) {
-            s.append("FullTracking");
+            s.append(", FullTracking");
         }
         if (mCorrelationVectorOutputsEnabled) {
-            s.append(", CorrelationVectorOutPuts");
+            s.append(", CorrelationVectorOutputs");
         }
         s.append(']');
         return s.toString();
@@ -115,12 +138,15 @@
         if (mCorrelationVectorOutputsEnabled != other.mCorrelationVectorOutputsEnabled) {
             return false;
         }
+        if (mIntervalMillis != other.mIntervalMillis) {
+            return false;
+        }
         return true;
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(mFullTracking, mCorrelationVectorOutputsEnabled);
+        return Objects.hash(mFullTracking, mCorrelationVectorOutputsEnabled, mIntervalMillis);
     }
 
     @Override
@@ -132,6 +158,7 @@
     public static final class Builder {
         private boolean mCorrelationVectorOutputsEnabled;
         private boolean mFullTracking;
+        private int mIntervalMillis;
 
         /**
          * Constructs a {@link Builder} instance.
@@ -145,6 +172,7 @@
         public Builder(@NonNull GnssMeasurementRequest request) {
             mCorrelationVectorOutputsEnabled = request.isCorrelationVectorOutputsEnabled();
             mFullTracking = request.isFullTracking();
+            mIntervalMillis = request.getIntervalMillis();
         }
 
         /**
@@ -183,10 +211,25 @@
             return this;
         }
 
+        /**
+         * Set the time interval between the reported measurements in milliseconds, which is 0 by
+         * default.
+         *
+         * <p>An interval of 0 milliseconds means the fastest rate the chipset can report.
+         *
+         * <p>The GNSS chipset may report measurements with a rate faster than requested.
+         */
+        @NonNull public Builder setIntervalMillis(@IntRange(from = 0) int value) {
+            mIntervalMillis = Preconditions.checkArgumentInRange(value, 0, Integer.MAX_VALUE,
+                    "intervalMillis");
+            return this;
+        }
+
         /** Builds a {@link GnssMeasurementRequest} instance as specified by this builder. */
         @NonNull
         public GnssMeasurementRequest build() {
-            return new GnssMeasurementRequest(mFullTracking, mCorrelationVectorOutputsEnabled);
+            return new GnssMeasurementRequest(mFullTracking, mCorrelationVectorOutputsEnabled,
+                    mIntervalMillis);
         }
     }
 }
diff --git a/location/java/android/location/GnssSingleSatCorrection.java b/location/java/android/location/GnssSingleSatCorrection.java
index aeca562..262630b 100644
--- a/location/java/android/location/GnssSingleSatCorrection.java
+++ b/location/java/android/location/GnssSingleSatCorrection.java
@@ -26,6 +26,8 @@
 
 import com.android.internal.util.Preconditions;
 
+import java.util.Objects;
+
 /**
  * A container with measurement corrections for a single visible satellite
  *
@@ -119,15 +121,17 @@
     @Nullable
     private final GnssReflectingPlane mReflectingPlane;
 
-    private GnssSingleSatCorrection(Builder builder) {
-        mSingleSatCorrectionFlags = builder.mSingleSatCorrectionFlags;
-        mSatId = builder.mSatId;
-        mConstellationType = builder.mConstellationType;
-        mCarrierFrequencyHz = builder.mCarrierFrequencyHz;
-        mProbSatIsLos = builder.mProbSatIsLos;
-        mExcessPathLengthMeters = builder.mExcessPathLengthMeters;
-        mExcessPathLengthUncertaintyMeters = builder.mExcessPathLengthUncertaintyMeters;
-        mReflectingPlane = builder.mReflectingPlane;
+    private GnssSingleSatCorrection(int singleSatCorrectionFlags, int constellationType, int satId,
+            float carrierFrequencyHz, float probSatIsLos, float excessPathLengthMeters,
+            float excessPathLengthUncertaintyMeters, GnssReflectingPlane reflectingPlane) {
+        mSingleSatCorrectionFlags = singleSatCorrectionFlags;
+        mConstellationType = constellationType;
+        mSatId = satId;
+        mCarrierFrequencyHz = carrierFrequencyHz;
+        mProbSatIsLos = probSatIsLos;
+        mExcessPathLengthMeters = excessPathLengthMeters;
+        mExcessPathLengthUncertaintyMeters = excessPathLengthUncertaintyMeters;
+        mReflectingPlane = reflectingPlane;
     }
 
     /**
@@ -239,27 +243,49 @@
         return 0;
     }
 
+    @Override
+    public void writeToParcel(@NonNull Parcel parcel, int flags) {
+        parcel.writeInt(mSingleSatCorrectionFlags);
+        parcel.writeInt(mConstellationType);
+        parcel.writeInt(mSatId);
+        parcel.writeFloat(mCarrierFrequencyHz);
+        if (hasValidSatelliteLineOfSight()) {
+            parcel.writeFloat(mProbSatIsLos);
+        }
+        if (hasExcessPathLength()) {
+            parcel.writeFloat(mExcessPathLengthMeters);
+        }
+        if (hasExcessPathLengthUncertainty()) {
+            parcel.writeFloat(mExcessPathLengthUncertaintyMeters);
+        }
+        if (hasReflectingPlane()) {
+            mReflectingPlane.writeToParcel(parcel, flags);
+        }
+    }
+
     public static final Creator<GnssSingleSatCorrection> CREATOR =
             new Creator<GnssSingleSatCorrection>() {
                 @Override
                 @NonNull
                 public GnssSingleSatCorrection createFromParcel(@NonNull Parcel parcel) {
-                    int mSingleSatCorrectionFlags = parcel.readInt();
-                    boolean hasReflectingPlane =
-                            (mSingleSatCorrectionFlags & HAS_REFLECTING_PLANE_MASK) != 0;
-                    final GnssSingleSatCorrection.Builder singleSatCorrectionBuilder =
-                            new Builder()
-                                    .setConstellationType(parcel.readInt())
-                                    .setSatelliteId(parcel.readInt())
-                                    .setCarrierFrequencyHz(parcel.readFloat())
-                                    .setProbabilityLineOfSight(parcel.readFloat())
-                                    .setExcessPathLengthMeters(parcel.readFloat())
-                                    .setExcessPathLengthUncertaintyMeters(parcel.readFloat());
-                    if (hasReflectingPlane) {
-                        singleSatCorrectionBuilder.setReflectingPlane(
-                                GnssReflectingPlane.CREATOR.createFromParcel(parcel));
-                    }
-                    return singleSatCorrectionBuilder.build();
+                    int singleSatCorrectionFlags = parcel.readInt();
+                    int constellationType = parcel.readInt();
+                    int satId = parcel.readInt();
+                    float carrierFrequencyHz = parcel.readFloat();
+                    float probSatIsLos = (singleSatCorrectionFlags & HAS_PROB_SAT_IS_LOS_MASK) != 0
+                            ? parcel.readFloat() : 0;
+                    float excessPathLengthMeters =
+                            (singleSatCorrectionFlags & HAS_EXCESS_PATH_LENGTH_MASK) != 0
+                                    ? parcel.readFloat() : 0;
+                    float excessPathLengthUncertaintyMeters =
+                            (singleSatCorrectionFlags & HAS_EXCESS_PATH_LENGTH_UNC_MASK) != 0
+                                    ? parcel.readFloat() : 0;
+                    GnssReflectingPlane reflectingPlane =
+                            (singleSatCorrectionFlags & HAS_REFLECTING_PLANE_MASK) != 0
+                                    ? GnssReflectingPlane.CREATOR.createFromParcel(parcel) : null;
+                    return new GnssSingleSatCorrection(singleSatCorrectionFlags, constellationType,
+                            satId, carrierFrequencyHz, probSatIsLos, excessPathLengthMeters,
+                            excessPathLengthUncertaintyMeters, reflectingPlane);
                 }
 
                 @Override
@@ -268,41 +294,94 @@
                 }
             };
 
-    @NonNull
     @Override
-    public String toString() {
-        final String format = "   %-29s = %s\n";
-        StringBuilder builder = new StringBuilder("GnssSingleSatCorrection:\n");
-        builder.append(
-                String.format(format, "SingleSatCorrectionFlags = ", mSingleSatCorrectionFlags));
-        builder.append(String.format(format, "ConstellationType = ", mConstellationType));
-        builder.append(String.format(format, "SatId = ", mSatId));
-        builder.append(String.format(format, "CarrierFrequencyHz = ", mCarrierFrequencyHz));
-        builder.append(String.format(format, "ProbSatIsLos = ", mProbSatIsLos));
-        builder.append(String.format(format, "ExcessPathLengthMeters = ", mExcessPathLengthMeters));
-        builder.append(
-                String.format(
-                        format,
-                        "ExcessPathLengthUncertaintyMeters = ",
-                        mExcessPathLengthUncertaintyMeters));
-        if (hasReflectingPlane()) {
-            builder.append(String.format(format, "ReflectingPlane = ", mReflectingPlane));
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
         }
-        return builder.toString();
+        if (!(obj instanceof GnssSingleSatCorrection)) {
+            return false;
+        }
+
+        GnssSingleSatCorrection other = (GnssSingleSatCorrection) obj;
+        if (mConstellationType != other.mConstellationType) {
+            return false;
+        }
+        if (mSatId != other.mSatId) {
+            return false;
+        }
+        if (Float.compare(mCarrierFrequencyHz, other.mCarrierFrequencyHz) != 0) {
+            return false;
+        }
+
+        if (hasValidSatelliteLineOfSight() != other.hasValidSatelliteLineOfSight()) {
+            return false;
+        }
+        if (hasValidSatelliteLineOfSight()
+                && Float.compare(mProbSatIsLos, other.mProbSatIsLos) != 0) {
+            return false;
+        }
+
+        if (hasExcessPathLength() != other.hasExcessPathLength()) {
+            return false;
+        }
+        if (hasExcessPathLength()
+                && Float.compare(mExcessPathLengthMeters, other.mExcessPathLengthMeters) != 0) {
+            return false;
+        }
+
+        if (hasExcessPathLengthUncertainty() != other.hasExcessPathLengthUncertainty()) {
+            return false;
+        }
+        if (hasExcessPathLengthUncertainty() && Float.compare(mExcessPathLengthUncertaintyMeters,
+                other.mExcessPathLengthUncertaintyMeters) != 0) {
+            return false;
+        }
+
+        if (hasReflectingPlane() != other.hasReflectingPlane()) {
+            return false;
+        }
+        if (hasReflectingPlane()
+                && !mReflectingPlane.equals(other.mReflectingPlane)) {
+            return false;
+        }
+        return true;
     }
 
     @Override
-    public void writeToParcel(@NonNull Parcel parcel, int flags) {
-        parcel.writeInt(mSingleSatCorrectionFlags);
-        parcel.writeInt(mConstellationType);
-        parcel.writeInt(mSatId);
-        parcel.writeFloat(mCarrierFrequencyHz);
-        parcel.writeFloat(mProbSatIsLos);
-        parcel.writeFloat(mExcessPathLengthMeters);
-        parcel.writeFloat(mExcessPathLengthUncertaintyMeters);
-        if (hasReflectingPlane()) {
-            mReflectingPlane.writeToParcel(parcel, flags);
+    public int hashCode() {
+        return Objects.hash(mSingleSatCorrectionFlags,
+                mConstellationType,
+                mSatId,
+                mCarrierFrequencyHz,
+                mProbSatIsLos,
+                mExcessPathLengthMeters,
+                mExcessPathLengthUncertaintyMeters,
+                mReflectingPlane);
+    }
+
+    @NonNull
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder("GnssSingleSatCorrection:[");
+        builder.append(" ConstellationType=").append(mConstellationType);
+        builder.append(" SatId=").append(mSatId);
+        builder.append(" CarrierFrequencyHz=").append(mCarrierFrequencyHz);
+        if (hasValidSatelliteLineOfSight()) {
+            builder.append(" ProbSatIsLos=").append(mProbSatIsLos);
         }
+        if (hasExcessPathLength()) {
+            builder.append(" ExcessPathLengthMeters=").append(mExcessPathLengthMeters);
+        }
+        if (hasExcessPathLengthUncertainty()) {
+            builder.append(" ExcessPathLengthUncertaintyMeters=").append(
+                    mExcessPathLengthUncertaintyMeters);
+        }
+        if (hasReflectingPlane()) {
+            builder.append(" ReflectingPlane=").append(mReflectingPlane);
+        }
+        builder.append(']');
+        return builder.toString();
     }
 
     /** Builder for {@link GnssSingleSatCorrection} */
@@ -332,6 +411,7 @@
 
         /** Sets the Satellite ID defined in the ICD of the given constellation. */
         @NonNull public Builder setSatelliteId(@IntRange(from = 0) int satId) {
+            Preconditions.checkArgumentNonnegative(satId, "satId should be non-negative.");
             mSatId = satId;
             return this;
         }
@@ -339,6 +419,8 @@
         /** Sets the Carrier frequency in Hz. */
         @NonNull public Builder setCarrierFrequencyHz(
                 @FloatRange(from = 0.0f,  fromInclusive = false) float carrierFrequencyHz) {
+            Preconditions.checkArgument(
+                    carrierFrequencyHz >= 0, "carrierFrequencyHz should be non-negative.");
             mCarrierFrequencyHz = carrierFrequencyHz;
             return this;
         }
@@ -352,8 +434,18 @@
             Preconditions.checkArgumentInRange(
                     probSatIsLos, 0, 1, "probSatIsLos should be between 0 and 1.");
             mProbSatIsLos = probSatIsLos;
-            mSingleSatCorrectionFlags =
-                    (byte) (mSingleSatCorrectionFlags | HAS_PROB_SAT_IS_LOS_MASK);
+            mSingleSatCorrectionFlags |= HAS_PROB_SAT_IS_LOS_MASK;
+            return this;
+        }
+
+        /**
+         * Clears the line-of-sight probability of the satellite at the given location.
+         *
+         * <p>This is to negate {@link #setProbabilityLineOfSight} call.
+         */
+        @NonNull public Builder clearProbabilityLineOfSight() {
+            mProbSatIsLos = 0;
+            mSingleSatCorrectionFlags &= ~HAS_PROB_SAT_IS_LOS_MASK;
             return this;
         }
 
@@ -363,18 +455,42 @@
          */
         @NonNull public Builder setExcessPathLengthMeters(
                 @FloatRange(from = 0.0f) float excessPathLengthMeters) {
+            Preconditions.checkArgument(excessPathLengthMeters >= 0,
+                    "excessPathLengthMeters should be non-negative.");
             mExcessPathLengthMeters = excessPathLengthMeters;
-            mSingleSatCorrectionFlags =
-                    (byte) (mSingleSatCorrectionFlags | HAS_EXCESS_PATH_LENGTH_MASK);
+            mSingleSatCorrectionFlags |= HAS_EXCESS_PATH_LENGTH_MASK;
+            return this;
+        }
+
+        /**
+         * Clears the Excess path length.
+         *
+         * <p>This is to negate {@link #setExcessPathLengthMeters} call.
+         */
+        @NonNull public Builder clearExcessPathLengthMeters() {
+            mExcessPathLengthMeters = 0;
+            mSingleSatCorrectionFlags &= ~HAS_EXCESS_PATH_LENGTH_MASK;
             return this;
         }
 
         /** Sets the error estimate (1-sigma) for the Excess path length estimate */
         @NonNull public Builder setExcessPathLengthUncertaintyMeters(
                 @FloatRange(from = 0.0f) float excessPathLengthUncertaintyMeters) {
+            Preconditions.checkArgument(excessPathLengthUncertaintyMeters >= 0,
+                    "excessPathLengthUncertaintyMeters should be non-negative.");
             mExcessPathLengthUncertaintyMeters = excessPathLengthUncertaintyMeters;
-            mSingleSatCorrectionFlags =
-                    (byte) (mSingleSatCorrectionFlags | HAS_EXCESS_PATH_LENGTH_UNC_MASK);
+            mSingleSatCorrectionFlags |= HAS_EXCESS_PATH_LENGTH_UNC_MASK;
+            return this;
+        }
+
+        /**
+         * Clears the error estimate (1-sigma) for the Excess path length estimate
+         *
+         * <p>This is to negate {@link #setExcessPathLengthUncertaintyMeters} call.
+         */
+        @NonNull public Builder clearExcessPathLengthUncertaintyMeters() {
+            mExcessPathLengthUncertaintyMeters = 0;
+            mSingleSatCorrectionFlags &= ~HAS_EXCESS_PATH_LENGTH_UNC_MASK;
             return this;
         }
 
@@ -382,18 +498,23 @@
         @NonNull public Builder setReflectingPlane(@Nullable GnssReflectingPlane reflectingPlane) {
             mReflectingPlane = reflectingPlane;
             if (reflectingPlane != null) {
-                mSingleSatCorrectionFlags =
-                        (byte) (mSingleSatCorrectionFlags | HAS_REFLECTING_PLANE_MASK);
+                mSingleSatCorrectionFlags |= HAS_REFLECTING_PLANE_MASK;
             } else {
-                mSingleSatCorrectionFlags =
-                        (byte) (mSingleSatCorrectionFlags & ~HAS_REFLECTING_PLANE_MASK);
+                mSingleSatCorrectionFlags &= ~HAS_REFLECTING_PLANE_MASK;
             }
             return this;
         }
 
         /** Builds a {@link GnssSingleSatCorrection} instance as specified by this builder. */
         @NonNull public GnssSingleSatCorrection build() {
-            return new GnssSingleSatCorrection(this);
+            return new GnssSingleSatCorrection(mSingleSatCorrectionFlags,
+                    mConstellationType,
+                    mSatId,
+                    mCarrierFrequencyHz,
+                    mProbSatIsLos,
+                    mExcessPathLengthMeters,
+                    mExcessPathLengthUncertaintyMeters,
+                    mReflectingPlane);
         }
     }
 }
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index 9993ce9..85e49cc 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -1187,6 +1187,9 @@
                     case AudioSystem.STREAM_ACCESSIBILITY:
                         mContentType = CONTENT_TYPE_SPEECH;
                         break;
+                    case AudioSystem.STREAM_ASSISTANT:
+                        mContentType = CONTENT_TYPE_SPEECH;
+                        break;
                     default:
                         Log.e(TAG, "Invalid stream type " + streamType + " for AudioAttributes");
                 }
@@ -1611,6 +1614,8 @@
                 return USAGE_VOICE_COMMUNICATION_SIGNALLING;
             case AudioSystem.STREAM_ACCESSIBILITY:
                 return USAGE_ASSISTANCE_ACCESSIBILITY;
+            case AudioSystem.STREAM_ASSISTANT:
+                return USAGE_ASSISTANT;
             case AudioSystem.STREAM_TTS:
             default:
                 return USAGE_UNKNOWN;
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 0722417..21fc6ec 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1204,7 +1204,8 @@
      *
      * @hide
      */
-    @UnsupportedAppUsage
+    @SystemApi
+    @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
     public int getLastAudibleStreamVolume(int streamType) {
         final IAudioService service = getService();
         try {
@@ -2399,6 +2400,77 @@
     }
 
     //====================================================================
+    // Direct playback query
+
+    /** Return value for {@link #getDirectPlaybackSupport(AudioFormat, AudioAttributes)}:
+        direct playback not supported. */
+    public static final int DIRECT_PLAYBACK_NOT_SUPPORTED = AudioSystem.DIRECT_NOT_SUPPORTED;
+    /** Return value for {@link #getDirectPlaybackSupport(AudioFormat, AudioAttributes)}:
+        direct offload playback supported. Compressed offload is a variant of direct playback.
+        It is the feature that allows audio processing tasks to be done on the Android device but
+        not on the application processor, instead, it is handled by dedicated hardware such as audio
+        DSPs. That will allow the application processor to be idle as much as possible, which is
+        good for power saving. Compressed offload playback supports
+        {@link AudioTrack.StreamEventCallback} for event notifications. */
+    public static final int DIRECT_PLAYBACK_OFFLOAD_SUPPORTED =
+            AudioSystem.DIRECT_OFFLOAD_SUPPORTED;
+    /** Return value for {@link #getDirectPlaybackSupport(AudioFormat, AudioAttributes)}:
+        direct offload playback supported with gapless transitions. Compressed offload is a variant
+        of direct playback. It is the feature that allows audio processing tasks to be done on the
+        Android device but not on the application processor, instead, it is handled by dedicated
+        hardware such as audio DSPs. That will allow the application processor to be idle as much as
+        possible, which is good for power saving. Compressed offload playback supports
+        {@link AudioTrack.StreamEventCallback} for event notifications. Gapless transitions
+        indicates the ability to play consecutive audio tracks without an audio silence in
+        between. */
+    public static final int DIRECT_PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED =
+            AudioSystem.DIRECT_OFFLOAD_GAPLESS_SUPPORTED;
+    /** Return value for {@link #getDirectPlaybackSupport(AudioFormat, AudioAttributes)}:
+        direct playback supported. This value covers direct playback that is bitstream pass-through
+        such as compressed pass-through. */
+    public static final int DIRECT_PLAYBACK_BITSTREAM_SUPPORTED =
+            AudioSystem.DIRECT_BITSTREAM_SUPPORTED;
+
+    /** @hide */
+    @IntDef(flag = true, prefix = "DIRECT_PLAYBACK_", value = {
+            DIRECT_PLAYBACK_NOT_SUPPORTED,
+            DIRECT_PLAYBACK_OFFLOAD_SUPPORTED,
+            DIRECT_PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED,
+            DIRECT_PLAYBACK_BITSTREAM_SUPPORTED}
+    )
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface AudioDirectPlaybackMode {}
+
+    /**
+     * Returns a bitfield representing the different forms of direct playback currently available
+     * for a given audio format.
+     * <p>Direct playback means that the audio stream is not altered by the framework. The audio
+     * stream will not be resampled, volume scaled, downmixed or mixed with other content by
+     * the framework. But it may be wrapped in a higher level protocol such as IEC61937 for
+     * passthrough.
+     * <p>Checking for direct support can help the app select the representation of audio content
+     * that most closely matches the capabilities of the device and peripherals (e.g. A/V receiver)
+     * connected to it. Note that the provided stream can still be re-encoded or mixed with other
+     * streams, if needed.
+     * @param format the audio format (codec, sample rate, channels) being checked.
+     * @param attributes the {@link AudioAttributes} to be used for playback
+     * @return the direct playback mode available with given format and attributes. The returned
+     *         value will be {@link #DIRECT_PLAYBACK_NOT_SUPPORTED} or a combination of
+     *         {@link #DIRECT_PLAYBACK_OFFLOAD_SUPPORTED},
+     *         {@link #DIRECT_PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED} and
+     *         {@link #DIRECT_PLAYBACK_BITSTREAM_SUPPORTED}. Note that if
+     *         {@link #DIRECT_PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED} is present in the returned value,
+     *         then {@link #DIRECT_PLAYBACK_OFFLOAD_SUPPORTED} will be too.
+     */
+    @AudioDirectPlaybackMode
+    public static int getDirectPlaybackSupport(@NonNull AudioFormat format,
+                                               @NonNull AudioAttributes attributes) {
+        Objects.requireNonNull(format);
+        Objects.requireNonNull(attributes);
+        return AudioSystem.getDirectPlaybackSupport(format, attributes);
+    }
+
+    //====================================================================
     // Offload query
     /**
      * Returns whether offloaded playback of an audio format is supported on the device.
@@ -2458,7 +2530,9 @@
      *         {@link #PLAYBACK_OFFLOAD_SUPPORTED} if offload playback is supported or
      *         {@link #PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED} if gapless transitions are
      *         also supported.
+     * @deprecated Use {@link #getDirectPlaybackSupport(AudioFormat, AudioAttributes)} instead
      */
+    @Deprecated
     @AudioOffloadMode
     public static int getPlaybackOffloadSupport(@NonNull AudioFormat format,
             @NonNull AudioAttributes attributes) {
@@ -6788,56 +6862,63 @@
 
     /**
      * Returns a list of audio formats that corresponds to encoding formats
-     * supported on offload path for A2DP and LE audio playback.
+     * supported on offload path for A2DP playback.
      *
-     * @param deviceType Indicates the target device type {@link AudioSystem.DeviceType}
      * @return a list of {@link BluetoothCodecConfig} objects containing encoding formats
-     * supported for offload A2DP playback or a list of {@link BluetoothLeAudioCodecConfig}
-     * objects containing encoding formats supported for offload LE Audio playback
+     * supported for offload A2DP playback
      * @hide
      */
-    public List<?> getHwOffloadFormatsSupportedForBluetoothMedia(
-            @AudioSystem.DeviceType int deviceType) {
-        ArrayList<Integer> formatsList = new ArrayList<Integer>();
-        ArrayList<BluetoothCodecConfig> a2dpCodecConfigList = new ArrayList<BluetoothCodecConfig>();
-        ArrayList<BluetoothLeAudioCodecConfig> leAudioCodecConfigList =
-                new ArrayList<BluetoothLeAudioCodecConfig>();
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    public @NonNull List<BluetoothCodecConfig> getHwOffloadFormatsSupportedForA2dp() {
+        ArrayList<Integer> formatsList = new ArrayList<>();
+        ArrayList<BluetoothCodecConfig> codecConfigList = new ArrayList<>();
 
-        if (deviceType != AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP
-                && deviceType != AudioSystem.DEVICE_OUT_BLE_HEADSET) {
-            throw new IllegalArgumentException(
-                    "Illegal devicetype for the getHwOffloadFormatsSupportedForBluetoothMedia");
-        }
-
-        int status = AudioSystem.getHwOffloadFormatsSupportedForBluetoothMedia(deviceType,
-                                                                                formatsList);
+        int status = AudioSystem.getHwOffloadFormatsSupportedForBluetoothMedia(
+                AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, formatsList);
         if (status != AudioManager.SUCCESS) {
-            Log.e(TAG, "getHwOffloadFormatsSupportedForBluetoothMedia for deviceType "
-                    + deviceType + " failed:" + status);
-            return a2dpCodecConfigList;
+            Log.e(TAG, "getHwOffloadEncodingFormatsSupportedForA2DP failed:" + status);
+            return codecConfigList;
         }
 
-        if (deviceType == AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) {
-            for (Integer format : formatsList) {
-                int btSourceCodec = AudioSystem.audioFormatToBluetoothSourceCodec(format);
-                if (btSourceCodec != BluetoothCodecConfig.SOURCE_CODEC_TYPE_INVALID) {
-                    a2dpCodecConfigList.add(new BluetoothCodecConfig(btSourceCodec));
-                }
+        for (Integer format : formatsList) {
+            int btSourceCodec = AudioSystem.audioFormatToBluetoothSourceCodec(format);
+            if (btSourceCodec != BluetoothCodecConfig.SOURCE_CODEC_TYPE_INVALID) {
+                codecConfigList.add(new BluetoothCodecConfig(btSourceCodec));
             }
-            return a2dpCodecConfigList;
-        } else if (deviceType == AudioSystem.DEVICE_OUT_BLE_HEADSET) {
-            for (Integer format : formatsList) {
-                int btLeAudioCodec = AudioSystem.audioFormatToBluetoothLeAudioSourceCodec(format);
-                if (btLeAudioCodec != BluetoothLeAudioCodecConfig.SOURCE_CODEC_TYPE_INVALID) {
-                    leAudioCodecConfigList.add(new BluetoothLeAudioCodecConfig.Builder()
-                                                .setCodecType(btLeAudioCodec)
-                                                .build());
-                }
-            }
+        }
+        return codecConfigList;
+    }
+
+    /**
+     * Returns a list of audio formats that corresponds to encoding formats
+     * supported on offload path for Le audio playback.
+     *
+     * @return a list of {@link BluetoothLeAudioCodecConfig} objects containing encoding formats
+     * supported for offload Le Audio playback
+     * @hide
+     */
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    @NonNull
+    public List<BluetoothLeAudioCodecConfig> getHwOffloadFormatsSupportedForLeAudio() {
+        ArrayList<Integer> formatsList = new ArrayList<>();
+        ArrayList<BluetoothLeAudioCodecConfig> leAudioCodecConfigList = new ArrayList<>();
+
+        int status = AudioSystem.getHwOffloadFormatsSupportedForBluetoothMedia(
+                AudioSystem.DEVICE_OUT_BLE_HEADSET, formatsList);
+        if (status != AudioManager.SUCCESS) {
+            Log.e(TAG, "getHwOffloadEncodingFormatsSupportedForLeAudio failed:" + status);
             return leAudioCodecConfigList;
         }
-        Log.e(TAG, "Input deviceType " + deviceType + " doesn't support.");
-        return a2dpCodecConfigList;
+
+        for (Integer format : formatsList) {
+            int btLeAudioCodec = AudioSystem.audioFormatToBluetoothLeAudioSourceCodec(format);
+            if (btLeAudioCodec != BluetoothLeAudioCodecConfig.SOURCE_CODEC_TYPE_INVALID) {
+                leAudioCodecConfigList.add(new BluetoothLeAudioCodecConfig.Builder()
+                                            .setCodecType(btLeAudioCodec)
+                                            .build());
+            }
+        }
+        return leAudioCodecConfigList;
     }
 
     // Since we need to calculate the changes since THE LAST NOTIFICATION, and not since the
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index e8792b3..d2c49e0 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -1768,13 +1768,34 @@
 
     /**
      * @hide
+     * Direct playback modes supported by audio HAL implementation.
+     */
+    public static final int DIRECT_NOT_SUPPORTED = 0;
+    public static final int DIRECT_OFFLOAD_SUPPORTED = 1;
+    public static final int DIRECT_OFFLOAD_GAPLESS_SUPPORTED = 3;
+    public static final int DIRECT_BITSTREAM_SUPPORTED = 4;
+
+    /**
+     * @hide
      * Compressed audio offload decoding modes supported by audio HAL implementation.
      * Keep in sync with system/media/include/media/audio.h.
      */
-    public static final int OFFLOAD_NOT_SUPPORTED = 0;
-    public static final int OFFLOAD_SUPPORTED = 1;
+    public static final int OFFLOAD_NOT_SUPPORTED = DIRECT_NOT_SUPPORTED;
+    public static final int OFFLOAD_SUPPORTED = DIRECT_OFFLOAD_SUPPORTED;
     public static final int OFFLOAD_GAPLESS_SUPPORTED = 2;
 
+    /**
+     * @hide
+     * Returns how direct playback of an audio format is currently available on the device.
+     * @param format the audio format (codec, sample rate, channels) being checked.
+     * @param attributes the {@link AudioAttributes} to be used for playback
+     * @return the direct playback mode available with given format and attributes. Any combination
+     *         of {@link #DIRECT_NOT_SUPPORTED}, {@link #DIRECT_OFFLOAD_SUPPORTED},
+     *         {@link #DIRECT_OFFLOAD_GAPLESS_SUPPORTED} and {@link #DIRECT_BITSTREAM_SUPPORTED}.
+     */
+    public static native int getDirectPlaybackSupport(
+            @NonNull AudioFormat format, @NonNull AudioAttributes attributes);
+
     static int getOffloadSupport(@NonNull AudioFormat format, @NonNull AudioAttributes attr) {
         return native_get_offload_support(format.getEncoding(), format.getSampleRate(),
                 format.getChannelMask(), format.getChannelIndexMask(),
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index ea692b9..55c558f 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -1357,8 +1357,8 @@
                     throw new UnsupportedOperationException(
                             "Offload and low latency modes are incompatible");
                 }
-                if (AudioSystem.getOffloadSupport(mFormat, mAttributes)
-                        == AudioSystem.OFFLOAD_NOT_SUPPORTED) {
+                if (AudioSystem.getDirectPlaybackSupport(mFormat, mAttributes)
+                        == AudioSystem.DIRECT_NOT_SUPPORTED) {
                     throw new UnsupportedOperationException(
                             "Cannot create AudioTrack, offload format / attributes not supported");
                 }
@@ -1530,7 +1530,10 @@
      *   the audio data.
      * @param attributes a non-null {@link AudioAttributes} instance.
      * @return true if the given audio format can be played directly.
+     * @deprecated Use {@link AudioManager#getDirectPlaybackSupport(AudioFormat, AudioAttributes)}
+     *             instead.
      */
+    @Deprecated
     public static boolean isDirectPlaybackSupported(@NonNull AudioFormat format,
             @NonNull AudioAttributes attributes) {
         if (format == null) {
diff --git a/media/java/android/media/JetPlayer.java b/media/java/android/media/JetPlayer.java
index 875c6f5..7749564 100644
--- a/media/java/android/media/JetPlayer.java
+++ b/media/java/android/media/JetPlayer.java
@@ -31,35 +31,33 @@
 
 /**
  * JetPlayer provides access to JET content playback and control.
- * 
- * <p>Please refer to the JET Creator User Manual for a presentation of the JET interactive
- * music concept and how to use the JetCreator tool to create content to be player by JetPlayer.
- * 
+ *
+ * <p>Please refer to the
+ * <a href="https://developer.android.com/guide/topics/media/jet/jetcreator_manual">JET Creator User
+ * Manual</a> for a presentation of the JET interactive music concept and how to use the JetCreator
+ * tool to create content to be player by JetPlayer.
+ *
  * <p>Use of the JetPlayer class is based around the playback of a number of JET segments
  * sequentially added to a playback FIFO queue. The rendering of the MIDI content stored in each
  * segment can be dynamically affected by two mechanisms:
  * <ul>
- * <li>tracks in a segment can be muted or unmuted at any moment, individually or through
- *    a mask (to change the mute state of multiple tracks at once)</li>
- * <li>parts of tracks in a segment can be played at predefined points in the segment, in order
- *    to maintain synchronization with the other tracks in the segment. This is achieved through
- *    the notion of "clips", which can be triggered at any time, but that will play only at the
- *    right time, as authored in the corresponding JET file.</li>
+ *   <li>Tracks in a segment can be muted or unmuted at any moment, individually or through a mask
+ *       (to change the mute state of multiple tracks at once).
+ *   <li>Parts of tracks in a segment can be played at predefined points in the segment, in order to
+ *       maintain synchronization with the other tracks in the segment. This is achieved through the
+ *       notion of "clips", which can be triggered at any time, but that will play only at the right
+ *       time, as authored in the corresponding JET file.
  * </ul>
- * As a result of the rendering and playback of the JET segments, the user of the JetPlayer instance
- * can receive notifications from the JET engine relative to:
- * <ul>
- * <li>the playback state,</li>
- * <li>the number of segments left to play in the queue,</li>
- * <li>application controller events (CC80-83) to mark points in the MIDI segments.</li>
- * </ul>
- * Use {@link #getJetPlayer()} to construct a JetPlayer instance. JetPlayer is a singleton class.
- * </p>
  *
- * <div class="special reference">
- * <h3>Developer Guides</h3>
- * <p>For more information about how to use JetPlayer, read the
- * <a href="{@docRoot}guide/topics/media/jetplayer.html">JetPlayer</a> developer guide.</p></div>
+ * <p>As a result of the rendering and playback of the JET segments, the user of the JetPlayer
+ * instance can receive notifications from the JET engine relative to:
+ * <ul>
+ *   <li>Playback state
+ *   <li>Number of segments left to play in the queue
+ *   <li>Application controller events (CC80-83) to mark points in the MIDI segments
+ * </ul>
+ *
+ * <p>Use {@link #getJetPlayer()} to construct a JetPlayer instance. JetPlayer is a singleton class.
  */
 public class JetPlayer
 {    
@@ -140,7 +138,7 @@
     //------------------------
     /**
      * Factory method for the JetPlayer class.
-     * @return the singleton JetPlayer instance
+     * @return the singleton JetPlayer instance.
      */
     public static JetPlayer getJetPlayer() {
         if (singletonRef == null) {
@@ -203,7 +201,8 @@
     // Getters
     //------------------------
     /**
-     * Returns the maximum number of simultaneous MIDI tracks supported by JetPlayer
+     * Gets the maximum number of simultaneous MIDI tracks supported by JetPlayer.
+     * @return the maximum number of simultaneous MIDI tracks supported by JetPlayer.
      */
     public static int getMaxTracks() {
         return JetPlayer.MAXTRACKS;
@@ -459,10 +458,9 @@
     //------------------------
     /**
      * Sets the listener JetPlayer notifies when a JET event is generated by the rendering and
-     * playback engine.
-     * Notifications will be received in the same thread as the one in which the JetPlayer
-     * instance was created.
-     * @param listener
+     * playback engine. Notifications are received in the same thread as the one in which the
+     * JetPlayer instance was created.
+     * @param listener the listener that will be notified when a JET event is generated.
      */
     public void setEventListener(OnJetEventListener listener) {
         setEventListener(listener, null);
@@ -470,10 +468,9 @@
     
     /**
      * Sets the listener JetPlayer notifies when a JET event is generated by the rendering and
-     * playback engine.
-     * Use this method to receive JET events in the Handler associated with another
-     * thread than the one in which you created the JetPlayer instance.
-     * @param listener
+     * playback engine. Use this method to receive JET events in the Handler associated with
+     * another thread than the one in which you created the JetPlayer instance.
+     * @param listener the listener that will be notified when a JET event is generated.
      * @param handler the Handler that will receive the event notification messages.
      */
     public void setEventListener(OnJetEventListener listener, Handler handler) {
diff --git a/media/java/android/media/MediaActionSound.java b/media/java/android/media/MediaActionSound.java
index dcd4dce..ec56d61 100644
--- a/media/java/android/media/MediaActionSound.java
+++ b/media/java/android/media/MediaActionSound.java
@@ -16,8 +16,11 @@
 
 package android.media;
 
-import android.media.AudioManager;
+import android.content.Context;
 import android.media.SoundPool;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.util.Log;
 
 /**
@@ -104,6 +107,26 @@
     private static final int STATE_LOADING_PLAY_REQUESTED = 2;
     private static final int STATE_LOADED                 = 3;
 
+    /**
+     * <p>Returns true if the application must play the shutter sound in accordance
+     * to certain regional restrictions. </p>
+     *
+     * <p>If this method returns true, applications are strongly recommended to use
+     * MediaActionSound.play(SHUTTER_CLICK) or START_VIDEO_RECORDING whenever it captures
+     * images or video to storage or sends them over the network.</p>
+     */
+    public static boolean mustPlayShutterSound() {
+        boolean result = false;
+        IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
+        IAudioService audioService = IAudioService.Stub.asInterface(b);
+        try {
+            result = audioService.isCameraSoundForced();
+        } catch (RemoteException e) {
+            Log.e(TAG, "audio service is unavailable for queries, defaulting to false");
+        }
+        return result;
+    }
+
     private class SoundState {
         public final int name;
         public int id;
diff --git a/media/java/android/media/MediaExtractor.java b/media/java/android/media/MediaExtractor.java
index 7459e63..dab188e 100644
--- a/media/java/android/media/MediaExtractor.java
+++ b/media/java/android/media/MediaExtractor.java
@@ -250,6 +250,13 @@
             @NonNull FileDescriptor fd, long offset, long length) throws IOException;
 
     /**
+     * Sets the MediaCas instance to use. This should be called after a successful setDataSource()
+     * if at least one track reports mime type of
+     * {@link android.media.MediaFormat#MIMETYPE_AUDIO_SCRAMBLED} or
+     * {@link android.media.MediaFormat#MIMETYPE_VIDEO_SCRAMBLED}. Stream parsing will not proceed
+     * until a valid MediaCas object is provided.
+     *
+     * @param mediaCas the MediaCas object to use.
      * @deprecated Use the {@code Descrambler} system API instead, or DRM public APIs like
      *             {@link MediaDrm}.
      */
diff --git a/media/java/android/media/audiopolicy/AudioMixingRule.java b/media/java/android/media/audiopolicy/AudioMixingRule.java
index c912759..1f89f99 100644
--- a/media/java/android/media/audiopolicy/AudioMixingRule.java
+++ b/media/java/android/media/audiopolicy/AudioMixingRule.java
@@ -145,10 +145,8 @@
             final int match_rule = mRule & ~RULE_EXCLUSION_MASK;
             switch (match_rule) {
                 case RULE_MATCH_ATTRIBUTE_USAGE:
-                    dest.writeInt(mAttr.getSystemUsage());
-                    break;
                 case RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET:
-                    dest.writeInt(mAttr.getCapturePreset());
+                    mAttr.writeToParcel(dest, AudioAttributes.FLATTEN_TAGS/*flags*/);
                     break;
                 case RULE_MATCH_UID:
                 case RULE_MATCH_USERID:
@@ -266,12 +264,14 @@
     public boolean isForCallRedirection() {
         for (AudioMixMatchCriterion criterion : mCriteria) {
             if (criterion.mAttr != null
-                    && (criterion.mRule == RULE_MATCH_ATTRIBUTE_USAGE
-                        && criterion.mAttr.getUsage() == AudioAttributes.USAGE_VOICE_COMMUNICATION)
+                    && criterion.mAttr.isForCallRedirection()
+                    && ((criterion.mRule == RULE_MATCH_ATTRIBUTE_USAGE
+                        && (criterion.mAttr.getUsage() == AudioAttributes.USAGE_VOICE_COMMUNICATION
+                            || criterion.mAttr.getUsage()
+                                == AudioAttributes.USAGE_VOICE_COMMUNICATION_SIGNALLING))
                     || (criterion.mRule == RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET
-                        && criterion.mAttr.getCapturePreset()
-                            == MediaRecorder.AudioSource.VOICE_COMMUNICATION)
-                    && criterion.mAttr.isForCallRedirection()) {
+                        && (criterion.mAttr.getCapturePreset()
+                            == MediaRecorder.AudioSource.VOICE_COMMUNICATION)))) {
                 return true;
             }
         }
@@ -713,19 +713,8 @@
             Integer intProp = null;
             switch (match_rule) {
                 case RULE_MATCH_ATTRIBUTE_USAGE:
-                    int usage = in.readInt();
-                    if (AudioAttributes.isSystemUsage(usage)) {
-                        attr = new AudioAttributes.Builder()
-                                .setSystemUsage(usage).build();
-                    } else {
-                        attr = new AudioAttributes.Builder()
-                                .setUsage(usage).build();
-                    }
-                    break;
                 case RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET:
-                    int preset = in.readInt();
-                    attr = new AudioAttributes.Builder()
-                            .setInternalCapturePreset(preset).build();
+                    attr =  AudioAttributes.CREATOR.createFromParcel(in);
                     break;
                 case RULE_MATCH_UID:
                 case RULE_MATCH_USERID:
diff --git a/telephony/java/com/android/internal/telephony/euicc/IResultCallback.aidl b/media/java/android/media/tv/AdRequest.aidl
similarity index 76%
copy from telephony/java/com/android/internal/telephony/euicc/IResultCallback.aidl
copy to media/java/android/media/tv/AdRequest.aidl
index 69f479c..ebfd748 100644
--- a/telephony/java/com/android/internal/telephony/euicc/IResultCallback.aidl
+++ b/media/java/android/media/tv/AdRequest.aidl
@@ -13,11 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.internal.telephony.euicc;
 
-import android.content.Intent;
+package android.media.tv;
 
-/** @hide */
-oneway interface IResultCallback {
-    void onComplete(int resultCode, in Intent resultIntent);
-}
+parcelable AdRequest;
diff --git a/media/java/android/media/tv/AdRequest.java b/media/java/android/media/tv/AdRequest.java
new file mode 100644
index 0000000..536baf2
--- /dev/null
+++ b/media/java/android/media/tv/AdRequest.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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;
+
+import android.annotation.NonNull;
+import android.annotation.StringDef;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.ParcelFileDescriptor;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/** @hide */
+public final class AdRequest implements Parcelable {
+    @Retention(RetentionPolicy.SOURCE)
+    @StringDef(prefix = "REQUEST_TYPE_", value = {
+            REQUEST_TYPE_START,
+            REQUEST_TYPE_STOP
+    })
+    public @interface RequestType {}
+
+    public static final String REQUEST_TYPE_START = "START";
+    public static final String REQUEST_TYPE_STOP = "STOP";
+
+    public static final @NonNull Parcelable.Creator<AdRequest> CREATOR =
+            new Parcelable.Creator<AdRequest>() {
+                @Override
+                public AdRequest createFromParcel(Parcel source) {
+                    return new AdRequest(source);
+                }
+
+                @Override
+                public AdRequest[] newArray(int size) {
+                    return new AdRequest[size];
+                }
+            };
+
+    private final int mId;
+    private final @RequestType String mRequestType;
+    private final ParcelFileDescriptor mFileDescriptor;
+    private final long mStartTime;
+    private final long mStopTime;
+    private final long mEchoInterval;
+    private final String mMediaFileType;
+    private final Bundle mMetadata;
+
+    public AdRequest(int id, @RequestType String requestType, ParcelFileDescriptor fileDescriptor,
+            long startTime, long stopTime, long echoInterval, String mediaFileType,
+            Bundle metadata) {
+        mId = id;
+        mRequestType = requestType;
+        mFileDescriptor = fileDescriptor;
+        mStartTime = startTime;
+        mStopTime = stopTime;
+        mEchoInterval = echoInterval;
+        mMediaFileType = mediaFileType;
+        mMetadata = metadata;
+    }
+
+    private AdRequest(Parcel source) {
+        mId = source.readInt();
+        mRequestType = source.readString();
+        mFileDescriptor = source.readFileDescriptor();
+        mStartTime = source.readLong();
+        mStopTime = source.readLong();
+        mEchoInterval = source.readLong();
+        mMediaFileType = source.readString();
+        mMetadata = source.readBundle();
+    }
+
+    public int getId() {
+        return mId;
+    }
+
+    public @RequestType String getRequestType() {
+        return mRequestType;
+    }
+
+    public ParcelFileDescriptor getFileDescriptor() {
+        return mFileDescriptor;
+    }
+
+    public long getStartTime() {
+        return mStartTime;
+    }
+
+    public long getStopTime() {
+        return mStopTime;
+    }
+
+    public long getEchoInterval() {
+        return mEchoInterval;
+    }
+
+    public String getMediaFileType() {
+        return mMediaFileType;
+    }
+
+    public Bundle getMetadata() {
+        return mMetadata;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeInt(mId);
+        dest.writeString(mRequestType);
+        mFileDescriptor.writeToParcel(dest, flags);
+        dest.writeLong(mStartTime);
+        dest.writeLong(mStopTime);
+        dest.writeLong(mEchoInterval);
+        dest.writeString(mMediaFileType);
+        dest.writeBundle(mMetadata);
+    }
+}
diff --git a/telephony/java/com/android/internal/telephony/euicc/IResultCallback.aidl b/media/java/android/media/tv/AdResponse.aidl
similarity index 76%
copy from telephony/java/com/android/internal/telephony/euicc/IResultCallback.aidl
copy to media/java/android/media/tv/AdResponse.aidl
index 69f479c..9c09a0a 100644
--- a/telephony/java/com/android/internal/telephony/euicc/IResultCallback.aidl
+++ b/media/java/android/media/tv/AdResponse.aidl
@@ -13,11 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.internal.telephony.euicc;
 
-import android.content.Intent;
+package android.media.tv;
 
-/** @hide */
-oneway interface IResultCallback {
-    void onComplete(int resultCode, in Intent resultIntent);
-}
+parcelable AdResponse;
diff --git a/media/java/android/media/tv/AdResponse.java b/media/java/android/media/tv/AdResponse.java
new file mode 100644
index 0000000..28cf5ac
--- /dev/null
+++ b/media/java/android/media/tv/AdResponse.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 android.media.tv;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.StringDef;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/** @hide */
+public final class AdResponse implements Parcelable {
+    @Retention(RetentionPolicy.SOURCE)
+    @StringDef(prefix = "RESPONSE_TYPE_", value = {
+            RESPONSE_TYPE_PLAYING,
+            RESPONSE_TYPE_FINISHED,
+            RESPONSE_TYPE_STOPPED,
+            RESPONSE_TYPE_ERROR
+    })
+    public @interface ResponseType {}
+
+    public static final String RESPONSE_TYPE_PLAYING = "PLAYING";
+    public static final String RESPONSE_TYPE_FINISHED = "FINISHED";
+    public static final String RESPONSE_TYPE_STOPPED = "STOPPED";
+    public static final String RESPONSE_TYPE_ERROR = "ERROR";
+
+    public static final @NonNull Parcelable.Creator<AdResponse> CREATOR =
+            new Parcelable.Creator<AdResponse>() {
+                @Override
+                public AdResponse createFromParcel(Parcel source) {
+                    return new AdResponse(source);
+                }
+
+                @Override
+                public AdResponse[] newArray(int size) {
+                    return new AdResponse[size];
+                }
+            };
+
+    private final int mId;
+    private final @ResponseType String mResponseType;
+    private final Long mElapsedTime;
+
+    public AdResponse(int id, @ResponseType String responseType, @Nullable Long elapsedTime) {
+        mId = id;
+        mResponseType = responseType;
+        mElapsedTime = elapsedTime;
+    }
+
+    private AdResponse(Parcel source) {
+        mId = source.readInt();
+        mResponseType = source.readString();
+        mElapsedTime = (Long) source.readValue(Long.class.getClassLoader());
+    }
+
+    public int getId() {
+        return mId;
+    }
+
+    public @ResponseType String getResponseType() {
+        return mResponseType;
+    }
+
+    public Long getElapsedTime() {
+        return mElapsedTime;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeInt(mId);
+        dest.writeString(mResponseType);
+        dest.writeValue(mElapsedTime);
+    }
+}
diff --git a/media/java/android/media/tv/AitInfo.java b/media/java/android/media/tv/AitInfo.java
index 5f8487d..ff4c625 100644
--- a/media/java/android/media/tv/AitInfo.java
+++ b/media/java/android/media/tv/AitInfo.java
@@ -27,7 +27,7 @@
 public final class AitInfo implements Parcelable {
     static final String TAG = "AitInfo";
 
-    public static final Creator<AitInfo> CREATOR = new Creator<AitInfo>() {
+    public static final @NonNull Creator<AitInfo> CREATOR = new Creator<AitInfo>() {
         @Override
         public AitInfo createFromParcel(Parcel in) {
             return new AitInfo(in);
diff --git a/media/java/android/media/tv/ITvInputClient.aidl b/media/java/android/media/tv/ITvInputClient.aidl
index 6f7db4a..f4f55e4 100644
--- a/media/java/android/media/tv/ITvInputClient.aidl
+++ b/media/java/android/media/tv/ITvInputClient.aidl
@@ -17,11 +17,12 @@
 package android.media.tv;
 
 import android.content.ComponentName;
+import android.media.tv.AdResponse;
 import android.media.tv.AitInfo;
 import android.media.tv.BroadcastInfoResponse;
 import android.media.tv.ITvInputSession;
-import android.net.Uri;
 import android.media.tv.TvTrackInfo;
+import android.net.Uri;
 import android.os.Bundle;
 import android.view.InputChannel;
 
@@ -54,4 +55,7 @@
 
     // For broadcast info
     void onBroadcastInfoResponse(in BroadcastInfoResponse response, int seq);
+
+    // For ad response
+    void onAdResponse(in AdResponse response, int seq);
 }
diff --git a/media/java/android/media/tv/ITvInputManager.aidl b/media/java/android/media/tv/ITvInputManager.aidl
index 0070898..d34e636 100644
--- a/media/java/android/media/tv/ITvInputManager.aidl
+++ b/media/java/android/media/tv/ITvInputManager.aidl
@@ -20,6 +20,7 @@
 import android.content.Intent;
 import android.graphics.Rect;
 import android.media.PlaybackParams;
+import android.media.tv.AdRequest;
 import android.media.tv.BroadcastInfoRequest;
 import android.media.tv.DvbDeviceInfo;
 import android.media.tv.ITvInputClient;
@@ -46,6 +47,8 @@
     TvInputInfo getTvInputInfo(in String inputId, int userId);
     void updateTvInputInfo(in TvInputInfo inputInfo, int userId);
     int getTvInputState(in String inputId, int userId);
+    List<String> getAvailableExtensionInterfaceNames(in String inputId, int userId);
+    IBinder getExtensionInterface(in String inputId, in String name, int userId);
 
     List<TvContentRatingSystemInfo> getTvContentRatingSystemList(int userId);
 
@@ -102,6 +105,10 @@
 
     // For broadcast info
     void requestBroadcastInfo(in IBinder sessionToken, in BroadcastInfoRequest request, int userId);
+    void removeBroadcastInfo(in IBinder sessionToken, int id, int userId);
+
+    // For ad request
+    void requestAd(in IBinder sessionToken, in AdRequest request, int userId);
 
     // For TV input hardware binding
     List<TvInputHardwareInfo> getHardwareList();
diff --git a/media/java/android/media/tv/ITvInputService.aidl b/media/java/android/media/tv/ITvInputService.aidl
index 8ccf13a..64a23a2 100755
--- a/media/java/android/media/tv/ITvInputService.aidl
+++ b/media/java/android/media/tv/ITvInputService.aidl
@@ -26,18 +26,21 @@
  * Top-level interface to a TV input component (implemented in a Service).
  * @hide
  */
-oneway interface ITvInputService {
-    void registerCallback(in ITvInputServiceCallback callback);
-    void unregisterCallback(in ITvInputServiceCallback callback);
-    void createSession(in InputChannel channel, in ITvInputSessionCallback callback,
+interface ITvInputService {
+    oneway void registerCallback(in ITvInputServiceCallback callback);
+    oneway void unregisterCallback(in ITvInputServiceCallback callback);
+    oneway void createSession(in InputChannel channel, in ITvInputSessionCallback callback,
             in String inputId, in String sessionId);
-    void createRecordingSession(in ITvInputSessionCallback callback, in String inputId,
+    oneway void createRecordingSession(in ITvInputSessionCallback callback, in String inputId,
             in String sessionId);
+    List<String> getAvailableExtensionInterfaceNames();
+    IBinder getExtensionInterface(in String name);
+    String getExtensionInterfacePermission(in String name);
 
     // For hardware TvInputService
-    void notifyHardwareAdded(in TvInputHardwareInfo hardwareInfo);
-    void notifyHardwareRemoved(in TvInputHardwareInfo hardwareInfo);
-    void notifyHdmiDeviceAdded(in HdmiDeviceInfo deviceInfo);
-    void notifyHdmiDeviceRemoved(in HdmiDeviceInfo deviceInfo);
-    void notifyHdmiDeviceUpdated(in HdmiDeviceInfo deviceInfo);
+    oneway void notifyHardwareAdded(in TvInputHardwareInfo hardwareInfo);
+    oneway void notifyHardwareRemoved(in TvInputHardwareInfo hardwareInfo);
+    oneway void notifyHdmiDeviceAdded(in HdmiDeviceInfo deviceInfo);
+    oneway void notifyHdmiDeviceRemoved(in HdmiDeviceInfo deviceInfo);
+    oneway void notifyHdmiDeviceUpdated(in HdmiDeviceInfo deviceInfo);
 }
diff --git a/media/java/android/media/tv/ITvInputSession.aidl b/media/java/android/media/tv/ITvInputSession.aidl
index 984a551..f427501 100644
--- a/media/java/android/media/tv/ITvInputSession.aidl
+++ b/media/java/android/media/tv/ITvInputSession.aidl
@@ -18,6 +18,7 @@
 
 import android.graphics.Rect;
 import android.media.PlaybackParams;
+import android.media.tv.AdRequest;
 import android.media.tv.BroadcastInfoRequest;
 import android.media.tv.TvTrackInfo;
 import android.net.Uri;
@@ -66,4 +67,8 @@
 
     // For broadcast info
     void requestBroadcastInfo(in BroadcastInfoRequest request);
+    void removeBroadcastInfo(int id);
+
+    // For ad request
+    void requestAd(in AdRequest request);
 }
diff --git a/media/java/android/media/tv/ITvInputSessionCallback.aidl b/media/java/android/media/tv/ITvInputSessionCallback.aidl
index 9a0aaa3..9830e78 100644
--- a/media/java/android/media/tv/ITvInputSessionCallback.aidl
+++ b/media/java/android/media/tv/ITvInputSessionCallback.aidl
@@ -16,6 +16,7 @@
 
 package android.media.tv;
 
+import android.media.tv.AdResponse;
 import android.media.tv.AitInfo;
 import android.media.tv.BroadcastInfoResponse;
 import android.media.tv.ITvInputSession;
@@ -51,4 +52,7 @@
 
     // For broadcast info
     void onBroadcastInfoResponse(in BroadcastInfoResponse response);
+
+    // For ad response
+    void onAdResponse(in AdResponse response);
 }
diff --git a/media/java/android/media/tv/ITvInputSessionWrapper.java b/media/java/android/media/tv/ITvInputSessionWrapper.java
index 6539472..418ab2c 100644
--- a/media/java/android/media/tv/ITvInputSessionWrapper.java
+++ b/media/java/android/media/tv/ITvInputSessionWrapper.java
@@ -71,7 +71,9 @@
     private static final int DO_PAUSE_RECORDING = 22;
     private static final int DO_RESUME_RECORDING = 23;
     private static final int DO_REQUEST_BROADCAST_INFO = 24;
-    private static final int DO_SET_IAPP_NOTIFICATION_ENABLED = 25;
+    private static final int DO_REMOVE_BROADCAST_INFO = 25;
+    private static final int DO_SET_IAPP_NOTIFICATION_ENABLED = 26;
+    private static final int DO_REQUEST_AD = 27;
 
     private final boolean mIsRecordingSession;
     private final HandlerCaller mCaller;
@@ -240,10 +242,18 @@
                 mTvInputSessionImpl.requestBroadcastInfo((BroadcastInfoRequest) msg.obj);
                 break;
             }
+            case DO_REMOVE_BROADCAST_INFO: {
+                mTvInputSessionImpl.removeBroadcastInfo(msg.arg1);
+                break;
+            }
             case DO_SET_IAPP_NOTIFICATION_ENABLED: {
                 mTvInputSessionImpl.setIAppNotificationEnabled((Boolean) msg.obj);
                 break;
             }
+            case DO_REQUEST_AD: {
+                mTvInputSessionImpl.requestAd((AdRequest) msg.obj);
+                break;
+            }
             default: {
                 Log.w(TAG, "Unhandled message code: " + msg.what);
                 break;
@@ -404,6 +414,16 @@
         mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_REQUEST_BROADCAST_INFO, request));
     }
 
+    @Override
+    public void removeBroadcastInfo(int requestId) {
+        mCaller.executeOrSendMessage(mCaller.obtainMessageI(DO_REMOVE_BROADCAST_INFO, requestId));
+    }
+
+    @Override
+    public void requestAd(AdRequest request) {
+        mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_REQUEST_AD, request));
+    }
+
     private final class TvInputEventReceiver extends InputEventReceiver {
         public TvInputEventReceiver(InputChannel inputChannel, Looper looper) {
             super(inputChannel, looper);
diff --git a/media/java/android/media/tv/OWNERS b/media/java/android/media/tv/OWNERS
index 8bccc9a..33acd0d 100644
--- a/media/java/android/media/tv/OWNERS
+++ b/media/java/android/media/tv/OWNERS
@@ -1,5 +1,6 @@
 nchalko@google.com
 quxiangfang@google.com
+shubang@google.com
 
 # For android remote service
 per-file ITvRemoteServiceInput.aidl = file:/media/lib/tvremote/OWNERS
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index aeb3e3c..ad86002 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -731,6 +731,9 @@
                 @Override
                 public void run() {
                     mSessionCallback.onTracksChanged(mSession, tracks);
+                    if (mSession.mIAppNotificationEnabled && mSession.getIAppSession() != null) {
+                        mSession.getIAppSession().notifyTracksChanged(tracks);
+                    }
                 }
             });
         }
@@ -740,6 +743,9 @@
                 @Override
                 public void run() {
                     mSessionCallback.onTrackSelected(mSession, type, trackId);
+                    if (mSession.mIAppNotificationEnabled && mSession.getIAppSession() != null) {
+                        mSession.getIAppSession().notifyTrackSelected(type, trackId);
+                    }
                 }
             });
         }
@@ -888,6 +894,19 @@
                 });
             }
         }
+
+        void postAdResponse(final AdResponse response) {
+            if (mSession.mIAppNotificationEnabled) {
+                mHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        if (mSession.getIAppSession() != null) {
+                            mSession.getIAppSession().notifyAdResponse(response);
+                        }
+                    }
+                });
+            }
+        }
     }
 
     /**
@@ -1273,12 +1292,6 @@
                     }
                     record.postTuned(channelUri);
                     // TODO: synchronized and wrap the channelUri
-                    if (record.mSession.mIAppNotificationEnabled) {
-                        TvIAppManager.Session iappSession = record.mSession.mIAppSession;
-                        if (iappSession != null) {
-                            iappSession.notifyTuned(channelUri);
-                        }
-                    }
                 }
             }
 
@@ -1317,6 +1330,18 @@
                     record.postBroadcastInfoResponse(response);
                 }
             }
+
+            @Override
+            public void onAdResponse(AdResponse response, int seq) {
+                synchronized (mSessionCallbackRecordMap) {
+                    SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
+                    if (record == null) {
+                        Log.e(TAG, "Callback not found for seq " + seq);
+                        return;
+                    }
+                    record.postAdResponse(response);
+                }
+            }
         };
         ITvInputManagerCallback managerCallback = new ITvInputManagerCallback.Stub() {
             @Override
@@ -1474,6 +1499,57 @@
     }
 
     /**
+     * Returns available extension interfaces of a given hardware TV input. This can be used to
+     * provide domain-specific features that are only known between certain hardware TV inputs
+     * and their clients.
+     *
+     * @param inputId The ID of the TV input.
+     * @return a non-null list of extension interface names available to the caller. An empty
+     *         list indicates the given TV input is not found, or the given TV input is not a
+     *         hardware TV input, or the given TV input doesn't support any extension
+     *         interfaces, or the caller doesn't hold the required permission for the extension
+     *         interfaces supported by the given TV input.
+     * @see #getExtensionInterface
+     * @hide
+     */
+    @SystemApi
+    @NonNull
+    public List<String> getAvailableExtensionInterfaceNames(@NonNull String inputId) {
+        Preconditions.checkNotNull(inputId);
+        try {
+            return mService.getAvailableExtensionInterfaceNames(inputId, mUserId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Returns an extension interface of a given hardware TV input. This can be used to provide
+     * domain-specific features that are only known between certain hardware TV inputs and
+     * their clients.
+     *
+     * @param inputId The ID of the TV input.
+     * @param name The extension interface name.
+     * @return an {@link IBinder} for the given extension interface, {@code null} if the given TV
+     *         input is not found, or if the given TV input is not a hardware TV input, or if the
+     *         given TV input doesn't support the given extension interface, or if the caller
+     *         doesn't hold the required permission for the given extension interface.
+     * @see #getAvailableExtensionInterfaceNames
+     * @hide
+     */
+    @SystemApi
+    @Nullable
+    public IBinder getExtensionInterface(@NonNull String inputId, @NonNull String name) {
+        Preconditions.checkNotNull(inputId);
+        Preconditions.checkNotNull(name);
+        try {
+            return mService.getExtensionInterface(inputId, name, mUserId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Registers a {@link TvInputCallback}.
      *
      * @param callback A callback used to monitor status of the TV inputs.
@@ -2963,7 +3039,35 @@
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
+        }
 
+        /**
+         * Removes broadcast info.
+         * @param requestId the corresponding request ID sent from
+         *                  {@link #requestBroadcastInfo(android.media.tv.BroadcastInfoRequest)}
+         */
+        public void removeBroadcastInfo(int requestId) {
+            if (mToken == null) {
+                Log.w(TAG, "The session has been already released");
+                return;
+            }
+            try {
+                mService.removeBroadcastInfo(mToken, requestId, mUserId);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+
+        public void requestAd(AdRequest request) {
+            if (mToken == null) {
+                Log.w(TAG, "The session has been already released");
+                return;
+            }
+            try {
+                mService.requestAd(mToken, request, mUserId);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
         }
 
         private final class InputEventHandler extends Handler {
diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java
index 6743dd6..bd5a343 100755
--- a/media/java/android/media/tv/TvInputService.java
+++ b/media/java/android/media/tv/TvInputService.java
@@ -202,6 +202,21 @@
             }
 
             @Override
+            public List<String>  getAvailableExtensionInterfaceNames() {
+                return TvInputService.this.getAvailableExtensionInterfaceNames();
+            }
+
+            @Override
+            public IBinder getExtensionInterface(String name) {
+                return TvInputService.this.getExtensionInterface(name);
+            }
+
+            @Override
+            public String getExtensionInterfacePermission(String name) {
+                return TvInputService.this.getExtensionInterfacePermission(name);
+            }
+
+            @Override
             public void notifyHardwareAdded(TvInputHardwareInfo hardwareInfo) {
                 mServiceHandler.obtainMessage(ServiceHandler.DO_ADD_HARDWARE_INPUT,
                         hardwareInfo).sendToTarget();
@@ -254,6 +269,67 @@
     }
 
     /**
+     * Returns available extension interfaces. This can be used to provide domain-specific
+     * features that are only known between certain hardware TV inputs and their clients.
+     *
+     * <p>Note that this service-level extension interface mechanism is only for hardware
+     * TV inputs that are bound even when sessions are not created.
+     *
+     * @return a non-null list of available extension interface names. An empty list
+     *         indicates the TV input doesn't support any extension interfaces.
+     * @see #getExtensionInterface
+     * @see #getExtensionInterfacePermission
+     * @hide
+     */
+    @NonNull
+    @SystemApi
+    public List<String> getAvailableExtensionInterfaceNames() {
+        return new ArrayList<>();
+    }
+
+    /**
+     * Returns an extension interface. This can be used to provide domain-specific features
+     * that are only known between certain hardware TV inputs and their clients.
+     *
+     * <p>Note that this service-level extension interface mechanism is only for hardware
+     * TV inputs that are bound even when sessions are not created.
+     *
+     * @param name The extension interface name.
+     * @return an {@link IBinder} for the given extension interface, {@code null} if the TV input
+     *         doesn't support the given extension interface.
+     * @see #getAvailableExtensionInterfaceNames
+     * @see #getExtensionInterfacePermission
+     * @hide
+     */
+    @Nullable
+    @SystemApi
+    public IBinder getExtensionInterface(@NonNull String name) {
+        return null;
+    }
+
+    /**
+     * Returns a permission for the given extension interface. This can be used to provide
+     * domain-specific features that are only known between certain hardware TV inputs and their
+     * clients.
+     *
+     * <p>Note that this service-level extension interface mechanism is only for hardware
+     * TV inputs that are bound even when sessions are not created.
+     *
+     * @param name The extension interface name.
+     * @return a name of the permission being checked for the given extension interface,
+     *         {@code null} if there is no required permission, or if the TV input doesn't
+     *         support the given extension interface.
+     * @see #getAvailableExtensionInterfaceNames
+     * @see #getExtensionInterface
+     * @hide
+     */
+    @Nullable
+    @SystemApi
+    public String getExtensionInterfacePermission(@NonNull String name) {
+        return null;
+    }
+
+    /**
      * Returns a concrete implementation of {@link Session}.
      *
      * <p>May return {@code null} if this TV input service fails to create a session for some
@@ -773,7 +849,7 @@
         /**
          * Notifies response for broadcast info.
          *
-         * @param response
+         * @param response broadcast info response.
          * @hide
          */
         public void notifyBroadcastInfoResponse(@NonNull final BroadcastInfoResponse response) {
@@ -793,6 +869,29 @@
             });
         }
 
+        /**
+         * Notifies response for advertisement.
+         *
+         * @param response advertisement response.
+         * @hide
+         */
+        public void notifyAdResponse(@NonNull final AdResponse response) {
+            executeOrPostRunnableOnMainThread(new Runnable() {
+                @MainThread
+                @Override
+                public void run() {
+                    try {
+                        if (DEBUG) Log.d(TAG, "notifyAdResponse");
+                        if (mSessionCallback != null) {
+                            mSessionCallback.onAdResponse(response);
+                        }
+                    } catch (RemoteException e) {
+                        Log.w(TAG, "error in notifyAdResponse", e);
+                    }
+                }
+            });
+        }
+
         private void notifyTimeShiftStartPositionChanged(final long timeMs) {
             executeOrPostRunnableOnMainThread(new Runnable() {
                 @MainThread
@@ -962,6 +1061,8 @@
         public abstract void onSetStreamVolume(@FloatRange(from = 0.0, to = 1.0) float volume);
 
         /**
+         * called when broadcast info is requested.
+         *
          * @param request broadcast info request
          * @hide
          */
@@ -969,6 +1070,21 @@
         }
 
         /**
+         * @hide
+         */
+        public void onRemoveBroadcastInfo(int requestId) {
+        }
+
+        /**
+         * called when advertisement is requested.
+         *
+         * @param request advertisement request
+         * @hide
+         */
+        public void onRequestAd(@NonNull AdRequest request) {
+        }
+
+        /**
          * Tunes to a given channel.
          *
          * <p>No video will be displayed until {@link #notifyVideoAvailable()} is called.
@@ -1577,6 +1693,14 @@
             onRequestBroadcastInfo(request);
         }
 
+        void removeBroadcastInfo(int requestId) {
+            onRemoveBroadcastInfo(requestId);
+        }
+
+        void requestAd(AdRequest request) {
+            onRequestAd(request);
+        }
+
         /**
          * Takes care of dispatching incoming input events and tells whether the event was handled.
          */
diff --git a/media/java/android/media/tv/interactive/ITvIAppClient.aidl b/media/java/android/media/tv/interactive/ITvIAppClient.aidl
index a5f2331..892a800 100644
--- a/media/java/android/media/tv/interactive/ITvIAppClient.aidl
+++ b/media/java/android/media/tv/interactive/ITvIAppClient.aidl
@@ -16,7 +16,10 @@
 
 package android.media.tv.interactive;
 
+import android.graphics.Rect;
+import android.media.tv.AdRequest;
 import android.media.tv.BroadcastInfoRequest;
+import android.net.Uri;
 import android.os.Bundle;
 import android.view.InputChannel;
 
@@ -30,6 +33,14 @@
     void onSessionReleased(int seq);
     void onLayoutSurface(int left, int top, int right, int bottom, int seq);
     void onBroadcastInfoRequest(in BroadcastInfoRequest request, int seq);
+    void onRemoveBroadcastInfo(int id, int seq);
     void onSessionStateChanged(int state, int seq);
+    void onBiInteractiveAppCreated(in Uri biIAppUri, in String biIAppId, int seq);
     void onCommandRequest(in String cmdType, in Bundle parameters, int seq);
+    void onSetVideoBounds(in Rect rect, int seq);
+    void onRequestCurrentChannelUri(int seq);
+    void onRequestCurrentChannelLcn(int seq);
+    void onRequestStreamVolume(int seq);
+    void onRequestTrackInfoList(int seq);
+    void onAdRequest(in AdRequest request, int Seq);
 }
diff --git a/media/java/android/media/tv/interactive/ITvIAppManager.aidl b/media/java/android/media/tv/interactive/ITvIAppManager.aidl
index 40d8034..23201fa 100644
--- a/media/java/android/media/tv/interactive/ITvIAppManager.aidl
+++ b/media/java/android/media/tv/interactive/ITvIAppManager.aidl
@@ -17,7 +17,9 @@
 package android.media.tv.interactive;
 
 import android.graphics.Rect;
+import android.media.tv.AdResponse;
 import android.media.tv.BroadcastInfoResponse;
+import android.media.tv.TvTrackInfo;
 import android.media.tv.interactive.ITvIAppClient;
 import android.media.tv.interactive.ITvIAppManagerCallback;
 import android.media.tv.interactive.TvIAppInfo;
@@ -35,15 +37,26 @@
     void notifyAppLinkInfo(String tiasId, in Bundle info, int userId);
     void sendAppLinkCommand(String tiasId, in Bundle command, int userId);
     void startIApp(in IBinder sessionToken, int userId);
+    void stopIApp(in IBinder sessionToken, int userId);
+    void createBiInteractiveApp(
+            in IBinder sessionToken, in Uri biIAppUri, in Bundle params, int userId);
+    void destroyBiInteractiveApp(in IBinder sessionToken, in String biIAppId, int userId);
+    void sendCurrentChannelUri(in IBinder sessionToken, in Uri channelUri, int userId);
+    void sendCurrentChannelLcn(in IBinder sessionToken, int lcn, int userId);
+    void sendStreamVolume(in IBinder sessionToken, float volume, int userId);
+    void sendTrackInfoList(in IBinder sessionToken, in List<TvTrackInfo> tracks, int userId);
     void createSession(
             in ITvIAppClient client, in String iAppServiceId, int type, int seq, int userId);
     void releaseSession(in IBinder sessionToken, int userId);
     void notifyTuned(in IBinder sessionToken, in Uri channelUri, int userId);
+    void notifyTrackSelected(in IBinder sessionToken, int type, in String trackId, int userId);
+    void notifyTracksChanged(in IBinder sessionToken, in List<TvTrackInfo> tracks, int userId);
     void setSurface(in IBinder sessionToken, in Surface surface, int userId);
     void dispatchSurfaceChanged(in IBinder sessionToken, int format, int width, int height,
             int userId);
     void notifyBroadcastInfoResponse(in IBinder sessionToken, in BroadcastInfoResponse response,
             int UserId);
+    void notifyAdResponse(in IBinder sessionToken, in AdResponse response, int UserId);
 
     void createMediaView(in IBinder sessionToken, in IBinder windowToken, in Rect frame,
             int userId);
@@ -52,4 +65,4 @@
 
     void registerCallback(in ITvIAppManagerCallback callback, int userId);
     void unregisterCallback(in ITvIAppManagerCallback callback, int userId);
-}
\ No newline at end of file
+}
diff --git a/media/java/android/media/tv/interactive/ITvIAppSession.aidl b/media/java/android/media/tv/interactive/ITvIAppSession.aidl
index 0d37a2b..52f9a87 100644
--- a/media/java/android/media/tv/interactive/ITvIAppSession.aidl
+++ b/media/java/android/media/tv/interactive/ITvIAppSession.aidl
@@ -17,10 +17,13 @@
 package android.media.tv.interactive;
 
 import android.graphics.Rect;
+import android.media.tv.BroadcastInfoResponse;
 import android.net.Uri;
+import android.media.tv.AdResponse;
 import android.media.tv.BroadcastInfoResponse;
+import android.media.tv.TvTrackInfo;
+import android.os.Bundle;
 import android.view.Surface;
-import android.media.tv.BroadcastInfoResponse;
 
 /**
  * Sub-interface of ITvIAppService.aidl which is created per session and has its own context.
@@ -28,13 +31,23 @@
  */
 oneway interface ITvIAppSession {
     void startIApp();
+    void stopIApp();
+    void createBiInteractiveApp(in Uri biIAppUri, in Bundle params);
+    void destroyBiInteractiveApp(in String biIAppId);
+    void sendCurrentChannelUri(in Uri channelUri);
+    void sendCurrentChannelLcn(int lcn);
+    void sendStreamVolume(float volume);
+    void sendTrackInfoList(in List<TvTrackInfo> tracks);
     void release();
     void notifyTuned(in Uri channelUri);
+    void notifyTrackSelected(int type, in String trackId);
+    void notifyTracksChanged(in List<TvTrackInfo> tracks);
     void setSurface(in Surface surface);
     void dispatchSurfaceChanged(int format, int width, int height);
     void notifyBroadcastInfoResponse(in BroadcastInfoResponse response);
+    void notifyAdResponse(in AdResponse response);
 
     void createMediaView(in IBinder windowToken, in Rect frame);
     void relayoutMediaView(in Rect frame);
     void removeMediaView();
-}
\ No newline at end of file
+}
diff --git a/media/java/android/media/tv/interactive/ITvIAppSessionCallback.aidl b/media/java/android/media/tv/interactive/ITvIAppSessionCallback.aidl
index 66f5fc1..9b9e6af 100644
--- a/media/java/android/media/tv/interactive/ITvIAppSessionCallback.aidl
+++ b/media/java/android/media/tv/interactive/ITvIAppSessionCallback.aidl
@@ -16,9 +16,11 @@
 
 package android.media.tv.interactive;
 
+import android.graphics.Rect;
+import android.media.tv.AdRequest;
 import android.media.tv.BroadcastInfoRequest;
 import android.media.tv.interactive.ITvIAppSession;
-import android.media.tv.BroadcastInfoRequest;
+import android.net.Uri;
 import android.os.Bundle;
 
 /**
@@ -30,6 +32,14 @@
     void onSessionCreated(in ITvIAppSession session);
     void onLayoutSurface(int left, int top, int right, int bottom);
     void onBroadcastInfoRequest(in BroadcastInfoRequest request);
+    void onRemoveBroadcastInfo(int id);
     void onSessionStateChanged(int state);
+    void onBiInteractiveAppCreated(in Uri biIAppUri, in String biIAppId);
     void onCommandRequest(in String cmdType, in Bundle parameters);
+    void onSetVideoBounds(in Rect rect);
+    void onRequestCurrentChannelUri();
+    void onRequestCurrentChannelLcn();
+    void onRequestStreamVolume();
+    void onRequestTrackInfoList();
+    void onAdRequest(in AdRequest request);
 }
diff --git a/media/java/android/media/tv/interactive/TvIAppInfo.java b/media/java/android/media/tv/interactive/TvIAppInfo.java
index de3a47e..79d94cc 100644
--- a/media/java/android/media/tv/interactive/TvIAppInfo.java
+++ b/media/java/android/media/tv/interactive/TvIAppInfo.java
@@ -16,6 +16,8 @@
 
 package android.media.tv.interactive;
 
+import android.annotation.NonNull;
+import android.annotation.StringDef;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -34,6 +36,8 @@
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -45,6 +49,21 @@
     private static final boolean DEBUG = false;
     private static final String TAG = "TvIAppInfo";
 
+    @Retention(RetentionPolicy.SOURCE)
+    @StringDef(prefix = { "INTERACTIVE_APP_TYPE_" }, value = {
+            INTERACTIVE_APP_TYPE_HBBTV,
+            INTERACTIVE_APP_TYPE_ATSC,
+            INTERACTIVE_APP_TYPE_GINGA,
+    })
+    @interface InteractiveAppType {}
+
+    /** HbbTV interactive app type */
+    public static final String INTERACTIVE_APP_TYPE_HBBTV = "hbbtv";
+    /** ATSC interactive app type */
+    public static final String INTERACTIVE_APP_TYPE_ATSC = "atsc";
+    /** Ginga interactive app type */
+    public static final String INTERACTIVE_APP_TYPE_GINGA = "ginga";
+
     private final ResolveInfo mService;
     private final String mId;
     private List<String> mTypes = new ArrayList<>();
@@ -55,13 +74,13 @@
         mTypes = types;
     }
 
-    protected TvIAppInfo(Parcel in) {
+    private TvIAppInfo(@NonNull Parcel in) {
         mService = ResolveInfo.CREATOR.createFromParcel(in);
         mId = in.readString();
         in.readStringList(mTypes);
     }
 
-    public static final Creator<TvIAppInfo> CREATOR = new Creator<TvIAppInfo>() {
+    public static final @NonNull Creator<TvIAppInfo> CREATOR = new Creator<TvIAppInfo>() {
         @Override
         public TvIAppInfo createFromParcel(Parcel in) {
             return new TvIAppInfo(in);
@@ -79,12 +98,13 @@
     }
 
     @Override
-    public void writeToParcel(Parcel dest, int flags) {
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
         mService.writeToParcel(dest, flags);
         dest.writeString(mId);
         dest.writeStringList(mTypes);
     }
 
+    @NonNull
     public String getId() {
         return mId;
     }
@@ -105,6 +125,13 @@
     }
 
     /**
+     * Gets supported interactive app types
+     */
+    public List<String> getSupportedTypes() {
+        return new ArrayList<>(mTypes);
+    }
+
+    /**
      * A convenience builder for creating {@link TvIAppInfo} objects.
      */
     public static final class Builder {
@@ -120,7 +147,7 @@
          * @param component The name of the application component to be used for the
          *                  {@link TvIAppService}.
          */
-        public Builder(Context context, ComponentName component) {
+        public Builder(@NonNull Context context, @NonNull ComponentName component) {
             if (context == null) {
                 throw new IllegalArgumentException("context cannot be null.");
             }
@@ -140,6 +167,7 @@
          *
          * @return TvIAppInfo containing information about this TV IApp service.
          */
+        @NonNull
         public TvIAppInfo build() {
             ComponentName componentName = new ComponentName(mResolveInfo.serviceInfo.packageName,
                     mResolveInfo.serviceInfo.name);
@@ -183,7 +211,7 @@
                 CharSequence[] types = sa.getTextArray(
                         com.android.internal.R.styleable.TvIAppService_supportedTypes);
                 for (CharSequence cs : types) {
-                    mTypes.add(cs.toString());
+                    mTypes.add(cs.toString().toLowerCase());
                 }
 
                 sa.recycle();
diff --git a/media/java/android/media/tv/interactive/TvIAppManager.java b/media/java/android/media/tv/interactive/TvIAppManager.java
index 9390d8d..d1fd1df 100644
--- a/media/java/android/media/tv/interactive/TvIAppManager.java
+++ b/media/java/android/media/tv/interactive/TvIAppManager.java
@@ -22,9 +22,12 @@
 import android.annotation.SystemService;
 import android.content.Context;
 import android.graphics.Rect;
+import android.media.tv.AdRequest;
+import android.media.tv.AdResponse;
 import android.media.tv.BroadcastInfoRequest;
 import android.media.tv.BroadcastInfoResponse;
 import android.media.tv.TvInputManager;
+import android.media.tv.TvTrackInfo;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
@@ -244,6 +247,18 @@
             }
 
             @Override
+            public void onRemoveBroadcastInfo(int requestId, int seq) {
+                synchronized (mSessionCallbackRecordMap) {
+                    SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
+                    if (record == null) {
+                        Log.e(TAG, "Callback not found for seq " + seq);
+                        return;
+                    }
+                    record.postRemoveBroadcastInfo(requestId);
+                }
+            }
+
+            @Override
             public void onCommandRequest(@TvIAppService.IAppServiceCommandType String cmdType,
                     Bundle parameters, int seq) {
                 synchronized (mSessionCallbackRecordMap) {
@@ -257,6 +272,78 @@
             }
 
             @Override
+            public void onSetVideoBounds(Rect rect, int seq) {
+                synchronized (mSessionCallbackRecordMap) {
+                    SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
+                    if (record == null) {
+                        Log.e(TAG, "Callback not found for seq " + seq);
+                        return;
+                    }
+                    record.postSetVideoBounds(rect);
+                }
+            }
+
+            @Override
+            public void onAdRequest(AdRequest request, int seq) {
+                synchronized (mSessionCallbackRecordMap) {
+                    SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
+                    if (record == null) {
+                        Log.e(TAG, "Callback not found for seq " + seq);
+                        return;
+                    }
+                    record.postAdRequest(request);
+                }
+            }
+
+            @Override
+            public void onRequestCurrentChannelUri(int seq) {
+                synchronized (mSessionCallbackRecordMap) {
+                    SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
+                    if (record == null) {
+                        Log.e(TAG, "Callback not found for seq " + seq);
+                        return;
+                    }
+                    record.postRequestCurrentChannelUri();
+                }
+            }
+
+            @Override
+            public void onRequestCurrentChannelLcn(int seq) {
+                synchronized (mSessionCallbackRecordMap) {
+                    SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
+                    if (record == null) {
+                        Log.e(TAG, "Callback not found for seq " + seq);
+                        return;
+                    }
+                    record.postRequestCurrentChannelLcn();
+                }
+            }
+
+            @Override
+            public void onRequestStreamVolume(int seq) {
+                synchronized (mSessionCallbackRecordMap) {
+                    SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
+                    if (record == null) {
+                        Log.e(TAG, "Callback not found for seq " + seq);
+                        return;
+                    }
+                    record.postRequestStreamVolume();
+                }
+            }
+
+            @Override
+            public void onRequestTrackInfoList(int seq) {
+                synchronized (mSessionCallbackRecordMap) {
+                    SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
+                    if (record == null) {
+                        Log.e(TAG, "Callback not found for seq " + seq);
+                        return;
+                    }
+                    record.postRequestTrackInfoList();
+                }
+            }
+
+            @Override
             public void onSessionStateChanged(int state, int seq) {
                 synchronized (mSessionCallbackRecordMap) {
                     SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
@@ -267,6 +354,18 @@
                     record.postSessionStateChanged(state);
                 }
             }
+
+            @Override
+            public void onBiInteractiveAppCreated(Uri biIAppUri, String biIAppId, int seq) {
+                synchronized (mSessionCallbackRecordMap) {
+                    SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
+                    if (record == null) {
+                        Log.e(TAG, "Callback not found for seq " + seq);
+                        return;
+                    }
+                    record.postBiInteractiveAppCreated(biIAppUri, biIAppId);
+                }
+            }
         };
         ITvIAppManagerCallback managerCallback = new ITvIAppManagerCallback.Stub() {
             @Override
@@ -337,7 +436,7 @@
          *
          * @param iAppServiceId The ID of the TV IApp service.
          */
-        public void onIAppServiceAdded(String iAppServiceId) {
+        public void onIAppServiceAdded(@NonNull String iAppServiceId) {
         }
 
         /**
@@ -348,7 +447,7 @@
          *
          * @param iAppServiceId The ID of the TV IApp service.
          */
-        public void onIAppServiceRemoved(String iAppServiceId) {
+        public void onIAppServiceRemoved(@NonNull String iAppServiceId) {
         }
 
         /**
@@ -359,7 +458,7 @@
          *
          * @param iAppServiceId The ID of the TV IApp service.
          */
-        public void onIAppServiceUpdated(String iAppServiceId) {
+        public void onIAppServiceUpdated(@NonNull String iAppServiceId) {
         }
 
         /**
@@ -372,16 +471,15 @@
          *
          * @param iAppInfo The <code>TvIAppInfo</code> object that contains new information.
          */
-        public void onTvIAppInfoUpdated(TvIAppInfo iAppInfo) {
+        public void onTvIAppInfoUpdated(@NonNull TvIAppInfo iAppInfo) {
         }
 
-
         /**
          * This is called when the state of the interactive app service is changed.
          * @hide
          */
         public void onTvIAppServiceStateChanged(
-                String iAppServiceId, int type, @TvIAppRteState int state) {
+                @NonNull String iAppServiceId, int type, @TvIAppRteState int state) {
         }
     }
 
@@ -485,6 +583,7 @@
      *         information.
      * @hide
      */
+    @NonNull
     public List<TvIAppInfo> getTvIAppServiceList() {
         try {
             return mService.getTvIAppServiceList(mUserId);
@@ -497,7 +596,7 @@
      * Prepares TV IApp service for the given type.
      * @hide
      */
-    public void prepare(String tvIAppServiceId, int type) {
+    public void prepare(@NonNull String tvIAppServiceId, int type) {
         try {
             mService.prepare(tvIAppServiceId, type, mUserId);
         } catch (RemoteException e) {
@@ -509,7 +608,7 @@
      * Notifies app link info.
      * @hide
      */
-    public void notifyAppLinkInfo(String tvIAppServiceId, Bundle appLinkInfo) {
+    public void notifyAppLinkInfo(@NonNull String tvIAppServiceId, @NonNull Bundle appLinkInfo) {
         try {
             mService.notifyAppLinkInfo(tvIAppServiceId, appLinkInfo, mUserId);
         } catch (RemoteException e) {
@@ -622,6 +721,90 @@
             }
         }
 
+        void stopIApp() {
+            if (mToken == null) {
+                Log.w(TAG, "The session has been already released");
+                return;
+            }
+            try {
+                mService.stopIApp(mToken, mUserId);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+
+        void createBiInteractiveApp(Uri biIAppUri, Bundle params) {
+            if (mToken == null) {
+                Log.w(TAG, "The session has been already released");
+                return;
+            }
+            try {
+                mService.createBiInteractiveApp(mToken, biIAppUri, params, mUserId);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+
+        void destroyBiInteractiveApp(String biIAppId) {
+            if (mToken == null) {
+                Log.w(TAG, "The session has been already released");
+                return;
+            }
+            try {
+                mService.destroyBiInteractiveApp(mToken, biIAppId, mUserId);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+
+        void sendCurrentChannelUri(@Nullable Uri channelUri) {
+            if (mToken == null) {
+                Log.w(TAG, "The session has been already released");
+                return;
+            }
+            try {
+                mService.sendCurrentChannelUri(mToken, channelUri, mUserId);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+
+        void sendCurrentChannelLcn(int lcn) {
+            if (mToken == null) {
+                Log.w(TAG, "The session has been already released");
+                return;
+            }
+            try {
+                mService.sendCurrentChannelLcn(mToken, lcn, mUserId);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+
+        void sendStreamVolume(float volume) {
+            if (mToken == null) {
+                Log.w(TAG, "The session has been already released");
+                return;
+            }
+            try {
+                mService.sendStreamVolume(mToken, volume, mUserId);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+
+        void sendTrackInfoList(@NonNull List<TvTrackInfo> tracks) {
+            if (mToken == null) {
+                Log.w(TAG, "The session has been already released");
+                return;
+            }
+            try {
+                mService.sendTrackInfoList(mToken, tracks, mUserId);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+
         /**
          * Sets the {@link android.view.Surface} for this session.
          *
@@ -776,6 +959,23 @@
         }
 
         /**
+         * Notifies of any advertisement response passed in from TIS.
+         *
+         * @param response response passed in from TIS.
+         */
+        public void notifyAdResponse(AdResponse response) {
+            if (mToken == null) {
+                Log.w(TAG, "The session has been already released");
+                return;
+            }
+            try {
+                mService.notifyAdResponse(mToken, response, mUserId);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+
+        /**
          * Releases this session.
          */
         public void release() {
@@ -793,7 +993,7 @@
         }
 
         /**
-         * Notifies IAPP session when a channels is tuned.
+         * Notifies IAPP session when a channel is tuned.
          */
         public void notifyTuned(Uri channelUri) {
             if (mToken == null) {
@@ -807,6 +1007,36 @@
             }
         }
 
+        /**
+         * Notifies IAPP session when a track is selected.
+         */
+        public void notifyTrackSelected(int type, String trackId) {
+            if (mToken == null) {
+                Log.w(TAG, "The session has been already released");
+                return;
+            }
+            try {
+                mService.notifyTrackSelected(mToken, type, trackId, mUserId);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+
+        /**
+         * Notifies IAPP session when tracks are changed.
+         */
+        public void notifyTracksChanged(List<TvTrackInfo> tracks) {
+            if (mToken == null) {
+                Log.w(TAG, "The session has been already released");
+                return;
+            }
+            try {
+                mService.notifyTracksChanged(mToken, tracks, mUserId);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+
         private void flushPendingEventsLocked() {
             mHandler.removeMessages(InputEventHandler.MSG_FLUSH_INPUT_EVENT);
 
@@ -1059,6 +1289,15 @@
             });
         }
 
+        void postRemoveBroadcastInfo(final int requestId) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mSession.getInputSession().removeBroadcastInfo(requestId);
+                }
+            });
+        }
+
         void postCommandRequest(final @TvIAppService.IAppServiceCommandType String cmdType,
                 final Bundle parameters) {
             mHandler.post(new Runnable() {
@@ -1069,6 +1308,62 @@
             });
         }
 
+        void postSetVideoBounds(Rect rect) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mSessionCallback.onSetVideoBounds(mSession, rect);
+                }
+            });
+        }
+
+        void postRequestCurrentChannelUri() {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mSessionCallback.onRequestCurrentChannelUri(mSession);
+                }
+            });
+        }
+
+        void postRequestCurrentChannelLcn() {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mSessionCallback.onRequestCurrentChannelLcn(mSession);
+                }
+            });
+        }
+
+        void postRequestStreamVolume() {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mSessionCallback.onRequestStreamVolume(mSession);
+                }
+            });
+        }
+
+        void postRequestTrackInfoList() {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mSessionCallback.onRequestTrackInfoList(mSession);
+                }
+            });
+        }
+
+        void postAdRequest(final AdRequest request) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    if (mSession.getInputSession() != null) {
+                        mSession.getInputSession().requestAd(request);
+                    }
+                }
+            });
+        }
+
         void postSessionStateChanged(int state) {
             mHandler.post(new Runnable() {
                 @Override
@@ -1077,6 +1372,15 @@
                 }
             });
         }
+
+        void postBiInteractiveAppCreated(Uri biIAppUri, String biIAppId) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mSessionCallback.onBiInteractiveAppCreated(mSession, biIAppUri, biIAppId);
+                }
+            });
+        }
     }
 
     /**
@@ -1127,6 +1431,46 @@
         }
 
         /**
+         * This is called when {@link TvIAppService.Session#SetVideoBounds} is called.
+         *
+         * @param session A {@link TvIAppManager.Session} associated with this callback.
+         */
+        public void onSetVideoBounds(Session session, Rect rect) {
+        }
+
+        /**
+         * This is called when {@link TvIAppService.Session#RequestCurrentChannelUri} is called.
+         *
+         * @param session A {@link TvIAppManager.Session} associated with this callback.
+         */
+        public void onRequestCurrentChannelUri(Session session) {
+        }
+
+        /**
+         * This is called when {@link TvIAppService.Session#RequestCurrentChannelLcn} is called.
+         *
+         * @param session A {@link TvIAppManager.Session} associated with this callback.
+         */
+        public void onRequestCurrentChannelLcn(Session session) {
+        }
+
+        /**
+         * This is called when {@link TvIAppService.Session#RequestStreamVolume} is called.
+         *
+         * @param session A {@link TvIAppManager.Session} associated with this callback.
+         */
+        public void onRequestStreamVolume(Session session) {
+        }
+
+        /**
+         * This is called when {@link TvIAppService.Session#RequestTrackInfoList} is called.
+         *
+         * @param session A {@link TvIAppManager.Session} associated with this callback.
+         */
+        public void onRequestTrackInfoList(Session session) {
+        }
+
+        /**
          * This is called when {@link TvIAppService.Session#notifySessionStateChanged} is called.
          *
          * @param session A {@link TvIAppManager.Session} associated with this callback.
@@ -1134,5 +1478,18 @@
          */
         public void onSessionStateChanged(Session session, int state) {
         }
+
+        /**
+         * This is called when {@link TvIAppService.Session#notifyBiInteractiveAppCreated} is
+         * called.
+         *
+         * @param session A {@link TvIAppManager.Session} associated with this callback.
+         * @param biIAppUri URI associated this BI interactive app. This is the same URI in
+         *                  {@link Session#createBiInteractiveApp(Uri, Bundle)}
+         * @param biIAppId BI interactive app ID, which can be used to destroy the BI interactive
+         *                 app.
+         */
+        public void onBiInteractiveAppCreated(Session session, Uri biIAppUri, String biIAppId) {
+        }
     }
 }
diff --git a/media/java/android/media/tv/interactive/TvIAppService.java b/media/java/android/media/tv/interactive/TvIAppService.java
index 6475f90..1480ff64 100644
--- a/media/java/android/media/tv/interactive/TvIAppService.java
+++ b/media/java/android/media/tv/interactive/TvIAppService.java
@@ -27,8 +27,11 @@
 import android.content.Intent;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
+import android.media.tv.AdRequest;
+import android.media.tv.AdResponse;
 import android.media.tv.BroadcastInfoRequest;
 import android.media.tv.BroadcastInfoResponse;
+import android.media.tv.TvTrackInfo;
 import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.Bundle;
@@ -90,23 +93,26 @@
     @Retention(RetentionPolicy.SOURCE)
     @StringDef(prefix = "IAPP_SERVICE_COMMAND_TYPE_", value = {
             IAPP_SERVICE_COMMAND_TYPE_TUNE,
-            IAPP_SERVICE_COMMAND_TYPE_TUNENEXT,
-            IAPP_SERVICE_COMMAND_TYPE_TUNEPREV,
+            IAPP_SERVICE_COMMAND_TYPE_TUNE_NEXT,
+            IAPP_SERVICE_COMMAND_TYPE_TUNE_PREV,
             IAPP_SERVICE_COMMAND_TYPE_STOP,
-            IAPP_SERVICE_COMMAND_TYPE_SETSTREAMVOLUME
+            IAPP_SERVICE_COMMAND_TYPE_SET_STREAM_VOLUME,
+            IAPP_SERVICE_COMMAND_TYPE_SELECT_TRACK
     })
     public @interface IAppServiceCommandType {}
 
     /** @hide */
-    public static final String IAPP_SERVICE_COMMAND_TYPE_TUNE = "Tune";
+    public static final String IAPP_SERVICE_COMMAND_TYPE_TUNE = "tune";
     /** @hide */
-    public static final String IAPP_SERVICE_COMMAND_TYPE_TUNENEXT = "TuneNext";
+    public static final String IAPP_SERVICE_COMMAND_TYPE_TUNE_NEXT = "tune_next";
     /** @hide */
-    public static final String IAPP_SERVICE_COMMAND_TYPE_TUNEPREV = "TunePrevious";
+    public static final String IAPP_SERVICE_COMMAND_TYPE_TUNE_PREV = "tune_previous";
     /** @hide */
-    public static final String IAPP_SERVICE_COMMAND_TYPE_STOP = "Stop";
+    public static final String IAPP_SERVICE_COMMAND_TYPE_STOP = "stop";
     /** @hide */
-    public static final String IAPP_SERVICE_COMMAND_TYPE_SETSTREAMVOLUME = "setStreamVolume";
+    public static final String IAPP_SERVICE_COMMAND_TYPE_SET_STREAM_VOLUME = "set_stream_volume";
+    /** @hide */
+    public static final String IAPP_SERVICE_COMMAND_TYPE_SELECT_TRACK = "select_track";
 
     private final Handler mServiceHandler = new ServiceHandler();
     private final RemoteCallbackList<ITvIAppServiceCallback> mCallbacks =
@@ -244,7 +250,7 @@
          *
          * @param context The context of the application
          */
-        public Session(Context context) {
+        public Session(@NonNull Context context) {
             mContext = context;
             mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
             mHandler = new Handler(context.getMainLooper());
@@ -288,6 +294,63 @@
         }
 
         /**
+         * Stops TvIAppService session.
+         * @hide
+         */
+        public void onStopIApp() {
+        }
+
+        /**
+         * Creates broadcast-independent(BI) interactive application.
+         *
+         * @see #onDestroyBiInteractiveApp(String)
+         * @hide
+         */
+        public void onCreateBiInteractiveApp(@NonNull Uri biIAppUri, @Nullable Bundle params) {
+        }
+
+
+        /**
+         * Destroys broadcast-independent(BI) interactive application.
+         *
+         * @param biIAppId the BI interactive app ID from
+         *        {@link #createBiInteractiveApp(Uri, Bundle)}
+         *
+         * @see #onCreateBiInteractiveApp(Uri, Bundle)
+         * @hide
+         */
+        public void onDestroyBiInteractiveApp(@NonNull String biIAppId) {
+        }
+
+        /**
+         * Receives current channel URI.
+         * @hide
+         */
+        public void onCurrentChannelUri(@Nullable Uri channelUri) {
+        }
+
+        /**
+         * Receives logical channel number (LCN) of current channel.
+         * @hide
+         */
+        public void onCurrentChannelLcn(int lcn) {
+        }
+
+        /**
+         * Receives stream volume.
+         * @hide
+         */
+        public void onStreamVolume(float volume) {
+        }
+
+        /**
+         * Receives track list.
+         * @hide
+         */
+        public void onTrackInfoList(@NonNull List<TvTrackInfo> tracks) {
+        }
+
+        /**
          * Called when the application sets the surface.
          *
          * <p>The TV IApp service should render interactive app UI onto the given surface. When
@@ -332,6 +395,7 @@
          *
          * @return a view attached to the media window
          */
+        @Nullable
         public View onCreateMediaView() {
             return null;
         }
@@ -347,14 +411,35 @@
          * Called when the corresponding TV input tuned to a channel.
          * @hide
          */
-        public void onTuned(Uri channelUri) {
+        public void onTuned(@NonNull Uri channelUri) {
+        }
+
+        /**
+         * Called when the corresponding TV input selected to a track.
+         * @hide
+         */
+        public void onTrackSelected(int type, String trackId) {
+        }
+
+        /**
+         * Called when the tracks are changed.
+         * @hide
+         */
+        public void onTracksChanged(List<TvTrackInfo> tracks) {
         }
 
         /**
          * Called when a broadcast info response is received.
          * @hide
          */
-        public void onBroadcastInfoResponse(BroadcastInfoResponse response) {
+        public void onBroadcastInfoResponse(@NonNull BroadcastInfoResponse response) {
+        }
+
+        /**
+         * Called when an advertisement response is received.
+         * @hide
+         */
+        public void onAdResponse(AdResponse response) {
         }
 
         /**
@@ -362,7 +447,7 @@
          * @hide
          */
         @Override
-        public boolean onKeyDown(int keyCode, KeyEvent event) {
+        public boolean onKeyDown(int keyCode, @NonNull KeyEvent event) {
             return false;
         }
 
@@ -370,7 +455,7 @@
          * @hide
          */
         @Override
-        public boolean onKeyLongPress(int keyCode, KeyEvent event) {
+        public boolean onKeyLongPress(int keyCode, @NonNull KeyEvent event) {
             return false;
         }
 
@@ -378,7 +463,7 @@
          * @hide
          */
         @Override
-        public boolean onKeyMultiple(int keyCode, int count, KeyEvent event) {
+        public boolean onKeyMultiple(int keyCode, int count, @NonNull KeyEvent event) {
             return false;
         }
 
@@ -386,28 +471,28 @@
          * @hide
          */
         @Override
-        public boolean onKeyUp(int keyCode, KeyEvent event) {
+        public boolean onKeyUp(int keyCode, @NonNull KeyEvent event) {
             return false;
         }
 
         /**
          * @hide
          */
-        public boolean onTouchEvent(MotionEvent event) {
+        public boolean onTouchEvent(@NonNull MotionEvent event) {
             return false;
         }
 
         /**
          * @hide
          */
-        public boolean onTrackballEvent(MotionEvent event) {
+        public boolean onTrackballEvent(@NonNull MotionEvent event) {
             return false;
         }
 
         /**
          * @hide
          */
-        public boolean onGenericMotionEvent(MotionEvent event) {
+        public boolean onGenericMotionEvent(@NonNull MotionEvent event) {
             return false;
         }
 
@@ -469,6 +554,30 @@
         }
 
         /**
+         * Remove broadcast information request from the related TV input.
+         * @param requestId the ID of the request
+         */
+        public void removeBroadcastInfo(final int requestId) {
+            executeOrPostRunnableOnMainThread(new Runnable() {
+                @MainThread
+                @Override
+                public void run() {
+                    try {
+                        if (DEBUG) {
+                            Log.d(TAG, "removeBroadcastInfo (requestId="
+                                    + requestId + ")");
+                        }
+                        if (mSessionCallback != null) {
+                            mSessionCallback.onRemoveBroadcastInfo(requestId);
+                        }
+                    } catch (RemoteException e) {
+                        Log.w(TAG, "error in removeBroadcastInfo", e);
+                    }
+                }
+            });
+        }
+
+        /**
          * requests a specific command to be processed by the related TV input.
          * @param cmdType type of the specific command
          * @param parameters parameters of the specific command
@@ -493,10 +602,171 @@
             });
         }
 
+        /**
+         * Sets broadcast video bounds.
+         */
+        public void setVideoBounds(Rect rect) {
+            executeOrPostRunnableOnMainThread(new Runnable() {
+                @MainThread
+                @Override
+                public void run() {
+                    try {
+                        if (DEBUG) {
+                            Log.d(TAG, "setVideoBounds (rect=" + rect + ")");
+                        }
+                        if (mSessionCallback != null) {
+                            mSessionCallback.onSetVideoBounds(rect);
+                        }
+                    } catch (RemoteException e) {
+                        Log.w(TAG, "error in setVideoBounds", e);
+                    }
+                }
+            });
+        }
+
+        /**
+         * Requests the URI of the current channel.
+         */
+        public void requestCurrentChannelUri() {
+            executeOrPostRunnableOnMainThread(new Runnable() {
+                @MainThread
+                @Override
+                public void run() {
+                    try {
+                        if (DEBUG) {
+                            Log.d(TAG, "requestCurrentChannelUri");
+                        }
+                        if (mSessionCallback != null) {
+                            mSessionCallback.onRequestCurrentChannelUri();
+                        }
+                    } catch (RemoteException e) {
+                        Log.w(TAG, "error in requestCurrentChannelUri", e);
+                    }
+                }
+            });
+        }
+
+        /**
+         * Requests the logic channel number (LCN) of the current channel.
+         */
+        public void requestCurrentChannelLcn() {
+            executeOrPostRunnableOnMainThread(new Runnable() {
+                @MainThread
+                @Override
+                public void run() {
+                    try {
+                        if (DEBUG) {
+                            Log.d(TAG, "requestCurrentChannelLcn");
+                        }
+                        if (mSessionCallback != null) {
+                            mSessionCallback.onRequestCurrentChannelLcn();
+                        }
+                    } catch (RemoteException e) {
+                        Log.w(TAG, "error in requestCurrentChannelLcn", e);
+                    }
+                }
+            });
+        }
+
+        /**
+         * Requests stream volume.
+         */
+        public void requestStreamVolume() {
+            executeOrPostRunnableOnMainThread(new Runnable() {
+                @MainThread
+                @Override
+                public void run() {
+                    try {
+                        if (DEBUG) {
+                            Log.d(TAG, "requestStreamVolume");
+                        }
+                        if (mSessionCallback != null) {
+                            mSessionCallback.onRequestStreamVolume();
+                        }
+                    } catch (RemoteException e) {
+                        Log.w(TAG, "error in requestStreamVolume", e);
+                    }
+                }
+            });
+        }
+
+        /**
+         * Requests the list of {@link TvTrackInfo}.
+         */
+        public void requestTrackInfoList() {
+            executeOrPostRunnableOnMainThread(new Runnable() {
+                @MainThread
+                @Override
+                public void run() {
+                    try {
+                        if (DEBUG) {
+                            Log.d(TAG, "requestTrackInfoList");
+                        }
+                        if (mSessionCallback != null) {
+                            mSessionCallback.onRequestTrackInfoList();
+                        }
+                    } catch (RemoteException e) {
+                        Log.w(TAG, "error in requestTrackInfoList", e);
+                    }
+                }
+            });
+        }
+
+        /**
+         * requests an advertisement request to be processed by the related TV input.
+         * @param request advertisement request
+         */
+        public void requestAd(@NonNull final AdRequest request) {
+            executeOrPostRunnableOnMainThread(new Runnable() {
+                @MainThread
+                @Override
+                public void run() {
+                    try {
+                        if (DEBUG) {
+                            Log.d(TAG, "requestAd (id=" + request.getId() + ")");
+                        }
+                        if (mSessionCallback != null) {
+                            mSessionCallback.onAdRequest(request);
+                        }
+                    } catch (RemoteException e) {
+                        Log.w(TAG, "error in requestAd", e);
+                    }
+                }
+            });
+        }
+
         void startIApp() {
             onStartIApp();
         }
 
+        void stopIApp() {
+            onStopIApp();
+        }
+
+        void createBiInteractiveApp(@NonNull Uri biIAppUri, @Nullable Bundle params) {
+            onCreateBiInteractiveApp(biIAppUri, params);
+        }
+
+        void destroyBiInteractiveApp(@NonNull String biIAppId) {
+            onDestroyBiInteractiveApp(biIAppId);
+        }
+
+        void sendCurrentChannelUri(@Nullable Uri channelUri) {
+            onCurrentChannelUri(channelUri);
+        }
+
+        void sendCurrentChannelLcn(int lcn) {
+            onCurrentChannelLcn(lcn);
+        }
+
+        void sendStreamVolume(float volume) {
+            onStreamVolume(volume);
+        }
+
+        void sendTrackInfoList(@NonNull List<TvTrackInfo> tracks) {
+            onTrackInfoList(tracks);
+        }
+
         void release() {
             onRelease();
             if (mSurface != null) {
@@ -519,6 +789,20 @@
             onTuned(channelUri);
         }
 
+        void notifyTrackSelected(int type, String trackId) {
+            if (DEBUG) {
+                Log.d(TAG, "notifyTrackSelected (type=" + type + "trackId=" + trackId + ")");
+            }
+            onTrackSelected(type, trackId);
+        }
+
+        void notifyTracksChanged(List<TvTrackInfo> tracks) {
+            if (DEBUG) {
+                Log.d(TAG, "notifyTracksChanged (tracks=" + tracks + ")");
+            }
+            onTracksChanged(tracks);
+        }
+
 
         /**
          * Calls {@link #onBroadcastInfoResponse}.
@@ -532,6 +816,16 @@
         }
 
         /**
+         * Calls {@link #onAdResponse}.
+         */
+        void notifyAdResponse(AdResponse response) {
+            if (DEBUG) {
+                Log.d(TAG, "notifyAdResponse (requestId=" + response.getId() + ")");
+            }
+            onAdResponse(response);
+        }
+
+        /**
          * Notifies when the session state is changed.
          * @param state the current state.
          */
@@ -556,6 +850,32 @@
         }
 
         /**
+         * Notifies the broadcast-independent(BI) interactive application has been created.
+         * @param biIAppId BI interactive app ID, which can be used to destroy the BI interactive
+         *                 app.
+         * @hide
+         */
+        public final void notifyBiInteractiveAppCreated(Uri biIAppUri, String biIAppId) {
+            executeOrPostRunnableOnMainThread(new Runnable() {
+                @MainThread
+                @Override
+                public void run() {
+                    try {
+                        if (DEBUG) {
+                            Log.d(TAG, "notifyBiInteractiveAppCreated (biIAppId="
+                                    + biIAppId + ")");
+                        }
+                        if (mSessionCallback != null) {
+                            mSessionCallback.onBiInteractiveAppCreated(biIAppUri, biIAppId);
+                        }
+                    } catch (RemoteException e) {
+                        Log.w(TAG, "error in notifyBiInteractiveAppCreated", e);
+                    }
+                }
+            });
+        }
+
+        /**
          * Takes care of dispatching incoming input events and tells whether the event was handled.
          */
         int dispatchInputEvent(InputEvent event, InputEventReceiver receiver) {
@@ -793,6 +1113,41 @@
         }
 
         @Override
+        public void stopIApp() {
+            mSessionImpl.stopIApp();
+        }
+
+        @Override
+        public void createBiInteractiveApp(@NonNull Uri biIAppUri, @Nullable Bundle params) {
+            mSessionImpl.createBiInteractiveApp(biIAppUri, params);
+        }
+
+        @Override
+        public void destroyBiInteractiveApp(@NonNull String biIAppId) {
+            mSessionImpl.destroyBiInteractiveApp(biIAppId);
+        }
+
+        @Override
+        public void sendCurrentChannelUri(@Nullable Uri channelUri) {
+            mSessionImpl.sendCurrentChannelUri(channelUri);
+        }
+
+        @Override
+        public void sendCurrentChannelLcn(int lcn) {
+            mSessionImpl.sendCurrentChannelLcn(lcn);
+        }
+
+        @Override
+        public void sendStreamVolume(float volume) {
+            mSessionImpl.sendStreamVolume(volume);
+        }
+
+        @Override
+        public void sendTrackInfoList(@NonNull List<TvTrackInfo> tracks) {
+            mSessionImpl.sendTrackInfoList(tracks);
+        }
+
+        @Override
         public void release() {
             mSessionImpl.scheduleMediaViewCleanup();
             mSessionImpl.release();
@@ -804,6 +1159,16 @@
         }
 
         @Override
+        public void notifyTrackSelected(int type, final String trackId) {
+            mSessionImpl.notifyTrackSelected(type, trackId);
+        }
+
+        @Override
+        public void notifyTracksChanged(List<TvTrackInfo> tracks) {
+            mSessionImpl.notifyTracksChanged(tracks);
+        }
+
+        @Override
         public void setSurface(Surface surface) {
             mSessionImpl.setSurface(surface);
         }
@@ -819,6 +1184,11 @@
         }
 
         @Override
+        public void notifyAdResponse(AdResponse response) {
+            mSessionImpl.notifyAdResponse(response);
+        }
+
+        @Override
         public void createMediaView(IBinder windowToken, Rect frame) {
             mSessionImpl.createMediaView(windowToken, frame);
         }
diff --git a/media/java/android/media/tv/interactive/TvIAppView.java b/media/java/android/media/tv/interactive/TvIAppView.java
index efbe9e3..1ce14ae 100644
--- a/media/java/android/media/tv/interactive/TvIAppView.java
+++ b/media/java/android/media/tv/interactive/TvIAppView.java
@@ -16,6 +16,7 @@
 
 package android.media.tv.interactive;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
 import android.content.res.Resources;
@@ -23,9 +24,11 @@
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.media.tv.TvInputManager;
+import android.media.tv.TvTrackInfo;
 import android.media.tv.TvView;
 import android.media.tv.interactive.TvIAppManager.Session;
 import android.media.tv.interactive.TvIAppManager.SessionCallback;
+import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
 import android.util.AttributeSet;
@@ -37,6 +40,8 @@
 import android.view.View;
 import android.view.ViewGroup;
 
+import java.util.List;
+
 /**
  * Displays contents of interactive TV applications.
  * @hide
@@ -104,12 +109,16 @@
         }
     };
 
-    public TvIAppView(Context context) {
+    public TvIAppView(@NonNull Context context) {
         this(context, null, 0);
     }
 
-    public TvIAppView(Context context, AttributeSet attrs, int defStyleAttr) {
-        super(context, /* attrs = */null, /* defStyleAttr = */0);
+    public TvIAppView(@NonNull Context context, @Nullable AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public TvIAppView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
         int sourceResId = Resources.getAttributeSetSourceResId(attrs);
         if (sourceResId != Resources.ID_NULL) {
             Log.d(TAG, "Build local AttributeSet");
@@ -122,7 +131,7 @@
         }
         mDefStyleAttr = defStyleAttr;
         resetSurfaceView();
-        mTvIAppManager = (TvIAppManager) getContext().getSystemService("tv_interactive_app");
+        mTvIAppManager = (TvIAppManager) getContext().getSystemService(Context.TV_IAPP_SERVICE);
     }
 
     /**
@@ -266,7 +275,7 @@
     /**
      * Prepares the interactive application.
      */
-    public void prepareIApp(String iAppServiceId, int type) {
+    public void prepareIApp(@NonNull String iAppServiceId, int type) {
         // TODO: document and handle the cases that this method is called multiple times.
         if (DEBUG) {
             Log.d(TAG, "prepareIApp");
@@ -289,6 +298,66 @@
         }
     }
 
+    /**
+     * Stops the interactive application.
+     */
+    public void stopIApp() {
+        if (DEBUG) {
+            Log.d(TAG, "stopIApp");
+        }
+        if (mSession != null) {
+            mSession.stopIApp();
+        }
+    }
+
+    /**
+     * Sends current channel URI to related TV interactive app.
+     */
+    public void sendCurrentChannelUri(Uri channelUri) {
+        if (DEBUG) {
+            Log.d(TAG, "sendCurrentChannelUri");
+        }
+        if (mSession != null) {
+            mSession.sendCurrentChannelUri(channelUri);
+        }
+    }
+
+    /**
+     * Sends current channel logical channel number (LCN) to related TV interactive app.
+     */
+    public void sendCurrentChannelLcn(int lcn) {
+        if (DEBUG) {
+            Log.d(TAG, "sendCurrentChannelLcn");
+        }
+        if (mSession != null) {
+            mSession.sendCurrentChannelLcn(lcn);
+        }
+    }
+
+    /**
+     * Sends stream volume to related TV interactive app.
+     */
+    public void sendStreamVolume(float volume) {
+        if (DEBUG) {
+            Log.d(TAG, "sendStreamVolume");
+        }
+        if (mSession != null) {
+            mSession.sendStreamVolume(volume);
+        }
+    }
+
+    /**
+     * Sends track info list to related TV interactive app.
+     */
+    public void sendTrackInfoList(List<TvTrackInfo> tracks) {
+        if (DEBUG) {
+            Log.d(TAG, "sendTrackInfoList");
+        }
+        if (mSession != null) {
+            mSession.sendTrackInfoList(tracks);
+        }
+    }
+
     private void resetInternal() {
         mSessionCallback = null;
         if (mSession != null) {
@@ -301,6 +370,38 @@
         }
     }
 
+    /**
+     * Creates broadcast-independent(BI) interactive application.
+     *
+     * @see #destroyBiInteractiveApp(String)
+     * @hide
+     */
+    public void createBiInteractiveApp(@NonNull Uri biIAppUri, @Nullable Bundle params) {
+        if (DEBUG) {
+            Log.d(TAG, "createBiInteractiveApp Uri=" + biIAppUri + ", params=" + params);
+        }
+        if (mSession != null) {
+            mSession.createBiInteractiveApp(biIAppUri, params);
+        }
+    }
+
+    /**
+     * Destroys broadcast-independent(BI) interactive application.
+     *
+     * @param biIAppId the BI interactive app ID from {@link #createBiInteractiveApp(Uri, Bundle)}
+     *
+     * @see #createBiInteractiveApp(Uri, Bundle)
+     * @hide
+     */
+    public void destroyBiInteractiveApp(@NonNull String biIAppId) {
+        if (DEBUG) {
+            Log.d(TAG, "destroyBiInteractiveApp biIAppId=" + biIAppId);
+        }
+        if (mSession != null) {
+            mSession.destroyBiInteractiveApp(biIAppId);
+        }
+    }
+
     public Session getIAppSession() {
         return mSession;
     }
@@ -346,8 +447,72 @@
          * @param cmdType type of the command
          * @param parameters parameters of the command
          */
-        public void onCommandRequest(String iAppServiceId,
-                @TvIAppService.IAppServiceCommandType String cmdType, Bundle parameters) {
+        public void onCommandRequest(
+                @NonNull String iAppServiceId,
+                @NonNull @TvIAppService.IAppServiceCommandType String cmdType,
+                @Nullable Bundle parameters) {
+        }
+
+        /**
+         * This is called when the session state is changed.
+         *
+         * @param iAppServiceId The ID of the TV interactive app service bound to this view.
+         * @param state current session state.
+         */
+        public void onSessionStateChanged(@NonNull String iAppServiceId, int state) {
+        }
+
+        /**
+         * This is called when broadcast-independent (BI) interactive app is created.
+         *
+         * @param iAppServiceId The ID of the TV interactive app service bound to this view.
+         * @param biIAppUri URI associated this BI interactive app. This is the same URI in
+         *                  {@link Session#createBiInteractiveApp(Uri, Bundle)}
+         * @param biIAppId BI interactive app ID, which can be used to destroy the BI interactive
+         *                 app.
+         */
+        public void onBiInteractiveAppCreated(@NonNull String iAppServiceId, @NonNull Uri biIAppUri,
+                @Nullable String biIAppId) {
+        }
+
+        /**
+         * This is called when {@link TvIAppService.Session#SetVideoBounds} is called.
+         *
+         * @param iAppServiceId The ID of the TV interactive app service bound to this view.
+         */
+        public void onSetVideoBounds(@NonNull String iAppServiceId, @NonNull Rect rect) {
+        }
+
+        /**
+         * This is called when {@link TvIAppService.Session#RequestCurrentChannelUri} is called.
+         *
+         * @param iAppServiceId The ID of the TV interactive app service bound to this view.
+         */
+        public void onRequestCurrentChannelUri(@NonNull String iAppServiceId) {
+        }
+
+        /**
+         * This is called when {@link TvIAppService.Session#RequestCurrentChannelLcn} is called.
+         *
+         * @param iAppServiceId The ID of the TV interactive app service bound to this view.
+         */
+        public void onRequestCurrentChannelLcn(@NonNull String iAppServiceId) {
+        }
+
+        /**
+         * This is called when {@link TvIAppService.Session#RequestStreamVolume} is called.
+         *
+         * @param iAppServiceId The ID of the TV interactive app service bound to this view.
+         */
+        public void onRequestStreamVolume(@NonNull String iAppServiceId) {
+        }
+
+        /**
+         * This is called when {@link TvIAppService.Session#RequestTrackInfoList} is called.
+         *
+         * @param iAppServiceId The ID of the TV interactive app service bound to this view.
+         */
+        public void onRequestTrackInfoList(@NonNull String iAppServiceId) {
         }
     }
 
@@ -440,5 +605,104 @@
                 mCallback.onCommandRequest(mIAppServiceId, cmdType, parameters);
             }
         }
+
+        @Override
+        public void onSessionStateChanged(Session session, int state) {
+            if (DEBUG) {
+                Log.d(TAG, "onSessionStateChanged (state=" + state +  ")");
+            }
+            if (this != mSessionCallback) {
+                Log.w(TAG, "onSessionStateChanged - session not created");
+                return;
+            }
+            if (mCallback != null) {
+                mCallback.onSessionStateChanged(mIAppServiceId, state);
+            }
+        }
+
+        @Override
+        public void onBiInteractiveAppCreated(Session session, Uri biIAppUri, String biIAppId) {
+            if (DEBUG) {
+                Log.d(TAG, "onBiInteractiveAppCreated (biIAppUri=" + biIAppUri + ", biIAppId="
+                        + biIAppId + ")");
+            }
+            if (this != mSessionCallback) {
+                Log.w(TAG, "onBiInteractiveAppCreated - session not created");
+                return;
+            }
+            if (mCallback != null) {
+                mCallback.onBiInteractiveAppCreated(mIAppServiceId, biIAppUri, biIAppId);
+            }
+        }
+
+        @Override
+        public void onSetVideoBounds(Session session, Rect rect) {
+            if (DEBUG) {
+                Log.d(TAG, "onSetVideoBounds (rect=" + rect + ")");
+            }
+            if (this != mSessionCallback) {
+                Log.w(TAG, "onSetVideoBounds - session not created");
+                return;
+            }
+            if (mCallback != null) {
+                mCallback.onSetVideoBounds(mIAppServiceId, rect);
+            }
+        }
+
+        @Override
+        public void onRequestCurrentChannelUri(Session session) {
+            if (DEBUG) {
+                Log.d(TAG, "onRequestCurrentChannelUri");
+            }
+            if (this != mSessionCallback) {
+                Log.w(TAG, "onRequestCurrentChannelUri - session not created");
+                return;
+            }
+            if (mCallback != null) {
+                mCallback.onRequestCurrentChannelUri(mIAppServiceId);
+            }
+        }
+
+        @Override
+        public void onRequestCurrentChannelLcn(Session session) {
+            if (DEBUG) {
+                Log.d(TAG, "onRequestCurrentChannelLcn");
+            }
+            if (this != mSessionCallback) {
+                Log.w(TAG, "onRequestCurrentChannelLcn - session not created");
+                return;
+            }
+            if (mCallback != null) {
+                mCallback.onRequestCurrentChannelLcn(mIAppServiceId);
+            }
+        }
+
+        @Override
+        public void onRequestStreamVolume(Session session) {
+            if (DEBUG) {
+                Log.d(TAG, "onRequestStreamVolume");
+            }
+            if (this != mSessionCallback) {
+                Log.w(TAG, "onRequestStreamVolume - session not created");
+                return;
+            }
+            if (mCallback != null) {
+                mCallback.onRequestStreamVolume(mIAppServiceId);
+            }
+        }
+
+        @Override
+        public void onRequestTrackInfoList(Session session) {
+            if (DEBUG) {
+                Log.d(TAG, "onRequestTrackInfoList");
+            }
+            if (this != mSessionCallback) {
+                Log.w(TAG, "onRequestTrackInfoList - session not created");
+                return;
+            }
+            if (mCallback != null) {
+                mCallback.onRequestTrackInfoList(mIAppServiceId);
+            }
+        }
     }
 }
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index 255b391b..4128abf 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -19,6 +19,7 @@
 import android.annotation.BytesLong;
 import android.annotation.CallbackExecutor;
 import android.annotation.IntDef;
+import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
@@ -687,6 +688,9 @@
     private native FrontendInfo nativeGetFrontendInfo(int id);
     private native Filter nativeOpenFilter(int type, int subType, long bufferSize);
     private native TimeFilter nativeOpenTimeFilter();
+    private native String nativeGetFrontendHardwareInfo();
+    private native int nativeSetMaxNumberOfFrontends(int frontendType, int maxNumber);
+    private native int nativeGetMaxNumberOfFrontends(int frontendType);
 
     private native Lnb nativeOpenLnbByHandle(int handle);
     private native Lnb nativeOpenLnbByName(String name);
@@ -1278,6 +1282,83 @@
         return Arrays.asList(feInfoList);
     }
 
+    /**
+     * Gets the currently initialized and activated frontend hardware information. The return values
+     * would differ per device makers. E.g. RF chip version, Demod chip version, detailed status of
+     * dvbs blind scan, etc
+     *
+     * <p>This API is only supported by Tuner HAL 2.0 or higher. Unsupported version would return
+     * {@code null}. Use {@link TunerVersionChecker#getTunerVersion()} to check the version.
+     *
+     * @return The active frontend hardware information. {@code null} if the operation failed.
+     * @throws IllegalStateException if there is no active frontend currently.
+     */
+    @Nullable
+    public String getCurrentFrontendHardwareInfo() {
+        mFrontendLock.lock();
+        try {
+            if (!TunerVersionChecker.checkHigherOrEqualVersionTo(
+                        TunerVersionChecker.TUNER_VERSION_2_0, "Get Frontend hardware info")) {
+                return null;
+            }
+            if (mFrontend == null) {
+                throw new IllegalStateException("frontend is not initialized");
+            }
+            return nativeGetFrontendHardwareInfo();
+        } finally {
+            mFrontendLock.unlock();
+        }
+    }
+
+    /**
+     * Sets the maximum usable frontends number of a given frontend type. It is used to enable or
+     * disable frontends when cable connection status is changed by user.
+     *
+     * <p>This API is only supported by Tuner HAL 2.0 or higher. Unsupported version would return
+     * {@link RESULT_UNAVAILABLE}. Use {@link TunerVersionChecker#getTunerVersion()} to check the
+     * version.
+     *
+     * @param frontendType the {@link android.media.tv.tuner.frontend.FrontendSettings.Type} which
+     *                     the maximum usable number will be set.
+     * @param maxNumber the new maximum usable number.
+     * @return result status of the operation.
+     */
+    @Result
+    public int setMaxNumberOfFrontends(
+            @FrontendSettings.Type int frontendType, @IntRange(from = 0) int maxNumber) {
+        if (!TunerVersionChecker.checkHigherOrEqualVersionTo(
+                    TunerVersionChecker.TUNER_VERSION_2_0, "Set maximum Frontends")) {
+            return RESULT_UNAVAILABLE;
+        }
+        if (maxNumber < 0) {
+            return RESULT_INVALID_ARGUMENT;
+        }
+        int res = nativeSetMaxNumberOfFrontends(frontendType, maxNumber);
+        if (res == RESULT_SUCCESS) {
+            // TODO: b/211778848 Update Tuner Resource Manager.
+        }
+        return res;
+    }
+
+    /**
+     * Get the maximum usable frontends number of a given frontend type.
+     *
+     * <p>This API is only supported by Tuner HAL 2.0 or higher. Unsupported version would return
+     * {@code -1}. Use {@link TunerVersionChecker#getTunerVersion()} to check the version.
+     *
+     * @param frontendType the {@link android.media.tv.tuner.frontend.FrontendSettings.Type} which
+     *                     the maximum usable number will be queried.
+     * @return the maximum usable number of the queried frontend type.
+     */
+    @IntRange(from = -1)
+    public int getMaxNumberOfFrontends(@FrontendSettings.Type int frontendType) {
+        if (!TunerVersionChecker.checkHigherOrEqualVersionTo(
+                    TunerVersionChecker.TUNER_VERSION_2_0, "Set maximum Frontends")) {
+            return -1;
+        }
+        return nativeGetMaxNumberOfFrontends(frontendType);
+    }
+
     /** @hide */
     public FrontendInfo getFrontendInfoById(int id) {
         mFrontendLock.lock();
@@ -1353,6 +1434,24 @@
         }
     }
 
+    private void onUnlocked() {
+        Log.d(TAG, "Wrote Stats Log for unlocked event from scanning.");
+        FrameworkStatsLog.write(FrameworkStatsLog.TV_TUNER_STATE_CHANGED, mUserId,
+                FrameworkStatsLog.TV_TUNER_STATE_CHANGED__STATE__LOCKED);
+
+        synchronized (mScanCallbackLock) {
+            if (mScanCallbackExecutor != null && mScanCallback != null) {
+                mScanCallbackExecutor.execute(() -> {
+                    synchronized (mScanCallbackLock) {
+                        if (mScanCallback != null) {
+                            mScanCallback.onUnlocked();
+                        }
+                    }
+                });
+            }
+        }
+    }
+
     private void onScanStopped() {
         synchronized (mScanCallbackLock) {
             if (mScanCallbackExecutor != null && mScanCallback != null) {
@@ -1577,6 +1676,20 @@
         }
     }
 
+    private void onDvbtCellIdsReported(int[] dvbtCellIds) {
+        synchronized (mScanCallbackLock) {
+            if (mScanCallbackExecutor != null && mScanCallback != null) {
+                mScanCallbackExecutor.execute(() -> {
+                    synchronized (mScanCallbackLock) {
+                        if (mScanCallback != null) {
+                            mScanCallback.onDvbtCellIdsReported(dvbtCellIds);
+                        }
+                    }
+                });
+            }
+        }
+    }
+
     /**
      * Opens a filter object based on the given types and buffer size.
      *
diff --git a/media/java/android/media/tv/tuner/filter/AvSettings.java b/media/java/android/media/tv/tuner/filter/AvSettings.java
index ed04754..15811d2 100644
--- a/media/java/android/media/tv/tuner/filter/AvSettings.java
+++ b/media/java/android/media/tv/tuner/filter/AvSettings.java
@@ -107,7 +107,8 @@
                     AUDIO_STREAM_TYPE_AAC, AUDIO_STREAM_TYPE_AC3, AUDIO_STREAM_TYPE_EAC3,
                     AUDIO_STREAM_TYPE_AC4, AUDIO_STREAM_TYPE_DTS, AUDIO_STREAM_TYPE_DTS_HD,
                     AUDIO_STREAM_TYPE_WMA, AUDIO_STREAM_TYPE_OPUS, AUDIO_STREAM_TYPE_VORBIS,
-                    AUDIO_STREAM_TYPE_DRA})
+                    AUDIO_STREAM_TYPE_DRA, AUDIO_STREAM_TYPE_AAC_ADTS, AUDIO_STREAM_TYPE_AAC_LATM,
+                    AUDIO_STREAM_TYPE_AAC_HE_ADTS, AUDIO_STREAM_TYPE_AAC_HE_LATM})
     @Retention(RetentionPolicy.SOURCE)
     public @interface AudioStreamType {}
 
@@ -182,6 +183,41 @@
      */
     public static final int AUDIO_STREAM_TYPE_DRA = android.hardware.tv.tuner.AudioStreamType.DRA;
 
+    /*
+     * AAC with ADTS (Audio Data Transport Format).
+     *
+     * This API is only supported by Tuner HAL 2.0 or higher. Use
+     * {@link TunerVersionChecker#getTunerVersion()} to check the version.
+     */
+    public static final int AUDIO_STREAM_TYPE_AAC_ADTS =
+            android.hardware.tv.tuner.AudioStreamType.AAC_ADTS;
+
+    /*
+     * AAC with ADTS with LATM (Low-overhead MPEG-4 Audio Transport Multiplex).
+     *
+     * This API is only supported by Tuner HAL 2.0 or higher. Use
+     * {@link TunerVersionChecker#getTunerVersion()} to check the version.
+     */
+    public static final int AUDIO_STREAM_TYPE_AAC_LATM =
+            android.hardware.tv.tuner.AudioStreamType.AAC_LATM;
+
+    /*
+     * High-Efficiency AAC (HE-AAC) with ADTS (Audio Data Transport Format).
+     *
+     * This API is only supported by Tuner HAL 2.0 or higher. Use
+     * {@link TunerVersionChecker#getTunerVersion()} to check the version.
+     */
+    public static final int AUDIO_STREAM_TYPE_AAC_HE_ADTS =
+            android.hardware.tv.tuner.AudioStreamType.AAC_HE_ADTS;
+
+    /*
+     * High-Efficiency AAC (HE-AAC) with LATM (Low-overhead MPEG-4 Audio Transport Multiplex).
+     *
+     * This API is only supported by Tuner HAL 2.0 or higher. Use
+     * {@link TunerVersionChecker#getTunerVersion()} to check the version.
+     */
+    public static final int AUDIO_STREAM_TYPE_AAC_HE_LATM =
+            android.hardware.tv.tuner.AudioStreamType.AAC_HE_LATM;
 
     private final boolean mIsPassthrough;
     private int mAudioStreamType = AUDIO_STREAM_TYPE_UNDEFINED;
diff --git a/media/java/android/media/tv/tuner/filter/Filter.java b/media/java/android/media/tv/tuner/filter/Filter.java
index 5d71a13..f9fc17f 100644
--- a/media/java/android/media/tv/tuner/filter/Filter.java
+++ b/media/java/android/media/tv/tuner/filter/Filter.java
@@ -254,6 +254,8 @@
     private native int nativeClose();
     private native String nativeAcquireSharedFilterToken();
     private native void nativeFreeSharedFilterToken(String token);
+    private native int nativeSetTimeDelayHint(int timeDelayInMs);
+    private native int nativeSetDataSizeDelayHint(int dataSizeDelayInBytes);
 
     // Called by JNI
     private Filter(long id) {
@@ -599,4 +601,52 @@
             mIsShared = false;
         }
     }
+
+    /**
+     * Set filter time delay.
+     *
+     * <p> Setting a time delay instructs the filter to delay its event callback invocation until
+     * the specified amount of time has passed. The default value (delay disabled) is {@code 0}.
+     *
+     * <p>This functionality is only available in Tuner version 2.0 and higher and will otherwise
+     * be a no-op. Use {@link TunerVersionChecker#getTunerVersion()} to get the version information.
+     *
+     * @param delayInMs specifies the duration of the delay in milliseconds.
+     */
+    public int delayCallbackUntilTimeMillis(long delayInMs) {
+        if (!TunerVersionChecker.checkHigherOrEqualVersionTo(
+                  TunerVersionChecker.TUNER_VERSION_2_0, "setTimeDelayHint")) {
+            return Tuner.RESULT_UNAVAILABLE;
+        }
+
+        if (delayInMs >= 0 && delayInMs <= Integer.MAX_VALUE) {
+            synchronized (mLock) {
+                return nativeSetTimeDelayHint((int) delayInMs);
+            }
+        }
+        return Tuner.RESULT_INVALID_ARGUMENT;
+    }
+
+    /**
+     * Set filter data size delay.
+     *
+     * <p> Setting a data size delay instructs the filter to delay its event callback invocation
+     * until a specified amount of data has accumulated. The default value (delay disabled) is
+     * {@code 0}.
+     *
+     * <p>This functionality is only available in Tuner version 2.0 and higher and will otherwise
+     * be a no-op. Use {@link TunerVersionChecker#getTunerVersion()} to get the version information.
+     *
+     * @param delayInBytes specifies the duration of the delay in bytes.
+     */
+    public int delayCallbackUntilBufferFilled(int delayInBytes) {
+        if (!TunerVersionChecker.checkHigherOrEqualVersionTo(
+                  TunerVersionChecker.TUNER_VERSION_2_0, "setTimeDelayHint")) {
+            return Tuner.RESULT_UNAVAILABLE;
+        }
+
+        synchronized (mLock) {
+            return nativeSetDataSizeDelayHint(delayInBytes);
+        }
+    }
 }
diff --git a/media/java/android/media/tv/tuner/filter/MediaEvent.java b/media/java/android/media/tv/tuner/filter/MediaEvent.java
index 79d4062..d958db1 100644
--- a/media/java/android/media/tv/tuner/filter/MediaEvent.java
+++ b/media/java/android/media/tv/tuner/filter/MediaEvent.java
@@ -49,12 +49,14 @@
     private final long mDataId;
     private final int mMpuSequenceNumber;
     private final boolean mIsPrivateData;
+    private final int mScIndexMask;
     private final AudioDescriptor mExtraMetaData;
 
     // This constructor is used by JNI code only
     private MediaEvent(int streamId, boolean isPtsPresent, long pts, boolean isDtsPresent, long dts,
             long dataLength, long offset, LinearBlock buffer, boolean isSecureMemory, long dataId,
-            int mpuSequenceNumber, boolean isPrivateData, AudioDescriptor extraMetaData) {
+            int mpuSequenceNumber, boolean isPrivateData, int scIndexMask,
+            AudioDescriptor extraMetaData) {
         mStreamId = streamId;
         mIsPtsPresent = isPtsPresent;
         mPts = pts;
@@ -67,6 +69,7 @@
         mDataId = dataId;
         mMpuSequenceNumber = mpuSequenceNumber;
         mIsPrivateData = isPrivateData;
+        mScIndexMask = scIndexMask;
         mExtraMetaData = extraMetaData;
     }
 
@@ -194,6 +197,17 @@
     }
 
     /**
+     * Gets SC (Start Code) index mask.
+     *
+     * <p>This API is only supported by Tuner HAL 2.0 or higher. Unsupported version would return
+     * {@code 0}. Use {@link TunerVersionChecker#getTunerVersion()} to check the version.
+     */
+    @RecordSettings.ScIndexMask
+    public int getScIndexMask() {
+        return mScIndexMask;
+    }
+
+    /**
      * Gets audio extra metadata.
      */
     @Nullable
diff --git a/media/java/android/media/tv/tuner/frontend/FrontendStatus.java b/media/java/android/media/tv/tuner/frontend/FrontendStatus.java
index 92eafec..8cedd04 100644
--- a/media/java/android/media/tv/tuner/frontend/FrontendStatus.java
+++ b/media/java/android/media/tv/tuner/frontend/FrontendStatus.java
@@ -53,7 +53,8 @@
             FRONTEND_STATUS_TYPE_MODULATIONS_EXT, FRONTEND_STATUS_TYPE_ROLL_OFF,
             FRONTEND_STATUS_TYPE_IS_MISO_ENABLED, FRONTEND_STATUS_TYPE_IS_LINEAR,
             FRONTEND_STATUS_TYPE_IS_SHORT_FRAMES_ENABLED, FRONTEND_STATUS_TYPE_ISDBT_MODE,
-            FRONTEND_STATUS_TYPE_ISDBT_PARTIAL_RECEPTION_FLAG, FRONTEND_STATUS_TYPE_STREAM_IDS})
+            FRONTEND_STATUS_TYPE_ISDBT_PARTIAL_RECEPTION_FLAG, FRONTEND_STATUS_TYPE_STREAM_IDS,
+            FRONTEND_STATUS_TYPE_DVBT_CELL_IDS})
     @Retention(RetentionPolicy.SOURCE)
     public @interface FrontendStatusType {}
 
@@ -260,6 +261,12 @@
     public static final int FRONTEND_STATUS_TYPE_STREAM_IDS =
             android.hardware.tv.tuner.FrontendStatusType.STREAM_ID_LIST;
 
+    /**
+     * DVB-T Cell IDs.
+     */
+    public static final int FRONTEND_STATUS_TYPE_DVBT_CELL_IDS =
+            android.hardware.tv.tuner.FrontendStatusType.DVBT_CELL_IDS;
+
     /** @hide */
     @IntDef(value = {
             AtscFrontendSettings.MODULATION_UNDEFINED,
@@ -500,6 +507,7 @@
     private Integer mIsdbtMode;
     private Integer mIsdbtPartialReceptionFlag;
     private int[] mStreamIds;
+    private int[] mDvbtCellIds;
 
     // Constructed and fields set by JNI code.
     private FrontendStatus() {
@@ -1052,6 +1060,24 @@
     }
 
     /**
+     * Gets DVB-T cell ids.
+     *
+     * <p>This query is only supported by Tuner HAL 2.0 or higher. Unsupported version or if HAL
+     * doesn't return cell ids will throw IllegalStateException. Use
+     * {@link TunerVersionChecker#getTunerVersion()} to check the version.
+     */
+    @SuppressLint("ArrayReturn")
+    @NonNull
+    public int[] getDvbtCellIds() {
+        TunerVersionChecker.checkHigherOrEqualVersionTo(
+                TunerVersionChecker.TUNER_VERSION_2_0, "dvbt cell ids status");
+        if (mDvbtCellIds == null) {
+            throw new IllegalStateException("dvbt cell ids are empty");
+        }
+        return mDvbtCellIds;
+    }
+
+    /**
      * Information of each tuning Physical Layer Pipes.
      */
     public static class Atsc3PlpTuningInfo {
diff --git a/media/java/android/media/tv/tuner/frontend/ScanCallback.java b/media/java/android/media/tv/tuner/frontend/ScanCallback.java
index cb35edb..68f3c1b 100644
--- a/media/java/android/media/tv/tuner/frontend/ScanCallback.java
+++ b/media/java/android/media/tv/tuner/frontend/ScanCallback.java
@@ -36,6 +36,9 @@
      */
     void onLocked();
 
+    /** Scan unlocked the signal. */
+    default void onUnlocked() {}
+
     /** Scan stopped. */
     void onScanStopped();
 
@@ -94,4 +97,7 @@
 
     /** DVBC Frontend Annex reported. */
     default void onDvbcAnnexReported(@DvbcFrontendSettings.Annex int dvbcAnnex) {}
+
+    /** DVBT Frontend Cell Ids reported. */
+    default void onDvbtCellIdsReported(@NonNull int[] dvbtCellIds) {}
 }
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index e91e238..c601649 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -62,6 +62,8 @@
 #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/FilterDelayHint.h>
+#include <aidl/android/hardware/tv/tuner/FilterDelayHintType.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>
@@ -210,6 +212,8 @@
 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::FilterDelayHint;
+using ::aidl::android::hardware::tv::tuner::FilterDelayHintType;
 using ::aidl::android::hardware::tv::tuner::FrontendAnalogAftFlag;
 using ::aidl::android::hardware::tv::tuner::FrontendAnalogSettings;
 using ::aidl::android::hardware::tv::tuner::FrontendAnalogSifStandard;
@@ -604,9 +608,11 @@
                                              const DemuxFilterEvent &event) {
     JNIEnv *env = AndroidRuntime::getJNIEnv();
     jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/MediaEvent");
-    jmethodID eventInit = env->GetMethodID(eventClazz, "<init>",
-                                           "(IZJZJJJLandroid/media/MediaCodec$LinearBlock;"
-                                           "ZJIZLandroid/media/tv/tuner/filter/AudioDescriptor;)V");
+    jmethodID eventInit = env->GetMethodID(
+            eventClazz,
+            "<init>",
+            "(IZJZJJJLandroid/media/MediaCodec$LinearBlock;"
+            "ZJIZILandroid/media/tv/tuner/filter/AudioDescriptor;)V");
     jfieldID eventContext = env->GetFieldID(eventClazz, "mNativeContext", "J");
 
     const DemuxFilterMediaEvent &mediaEvent = event.get<DemuxFilterEvent::Tag::media>();
@@ -639,10 +645,20 @@
     jlong avDataId = mediaEvent.avDataId;
     jint mpuSequenceNumber = mediaEvent.mpuSequenceNumber;
     jboolean isPesPrivateData = mediaEvent.isPesPrivateData;
+    jint sc = 0;
+    if (mediaEvent.scIndexMask.getTag() == DemuxFilterScIndexMask::Tag::scIndex) {
+        sc = mediaEvent.scIndexMask.get<DemuxFilterScIndexMask::Tag::scIndex>();
+    } else if (mediaEvent.scIndexMask.getTag() == DemuxFilterScIndexMask::Tag::scHevc) {
+        sc = mediaEvent.scIndexMask.get<DemuxFilterScIndexMask::Tag::scHevc>();
+    } else if (mediaEvent.scIndexMask.getTag() == DemuxFilterScIndexMask::Tag::scAvc) {
+        sc = mediaEvent.scIndexMask.get<DemuxFilterScIndexMask::Tag::scAvc>();
+        // Java uses the values defined by HIDL HAL. Left shift 4 bits.
+        sc = sc << 4;
+    }
 
     jobject obj = env->NewObject(eventClazz, eventInit, streamId, isPtsPresent, pts, isDtsPresent,
                                  dts, dataLength, offset, nullptr, isSecureMemory, avDataId,
-                                 mpuSequenceNumber, isPesPrivateData, audioDescriptor);
+                                 mpuSequenceNumber, isPesPrivateData, sc, audioDescriptor);
 
     uint64_t avSharedMemSize = mFilterClient->getAvSharedHandleInfo().size;
     if (mediaEvent.avMemory.fds.size() > 0 || mediaEvent.avDataId != 0 ||
@@ -1025,6 +1041,10 @@
                 env->CallVoidMethod(
                         frontend,
                         env->GetMethodID(clazz, "onLocked", "()V"));
+            } else {
+                env->CallVoidMethod(
+                        frontend,
+                        env->GetMethodID(clazz, "onUnlocked", "()V"));
             }
             break;
         }
@@ -1191,6 +1211,14 @@
                                 dvbcAnnex);
             break;
         }
+        case FrontendScanMessageType::DVBT_CELL_IDS: {
+            std::vector<int32_t> jintV = message.get<FrontendScanMessage::dvbtCellIds>();
+            jintArray cellIds = env->NewIntArray(jintV.size());
+            env->SetIntArrayRegion(cellIds, 0, jintV.size(), reinterpret_cast<jint *>(&jintV[0]));
+            env->CallVoidMethod(frontend, env->GetMethodID(clazz, "onDvbtCellIdsReported", "([I)V"),
+                                cellIds);
+            break;
+        }
         default:
             break;
     }
@@ -1540,6 +1568,33 @@
                           maxSymbolRate, acquireRange, exclusiveGroupId, statusCaps, jcaps);
 }
 
+Result JTuner::getFrontendHardwareInfo(string &info) {
+    if (mFeClient == nullptr) {
+        ALOGE("frontend is not initialized");
+        return Result::INVALID_STATE;
+    }
+
+    return mFeClient->getHardwareInfo(info);
+}
+
+jint JTuner::setMaxNumberOfFrontends(int32_t type, int32_t maxNumber) {
+    if (mTunerClient == nullptr) {
+        ALOGE("tuner is not initialized");
+        return (jint)Result::INVALID_STATE;
+    }
+
+    return (jint)mTunerClient->setMaxNumberOfFrontends(static_cast<FrontendType>(type), maxNumber);
+}
+
+int32_t JTuner::getMaxNumberOfFrontends(int32_t type) {
+    if (mTunerClient == nullptr) {
+        ALOGE("tuner is not initialized");
+        return -1;
+    }
+
+    return mTunerClient->getMaxNumberOfFrontends(static_cast<FrontendType>(type));
+}
+
 jobject JTuner::openLnbByHandle(int handle) {
     if (mTunerClient == nullptr) {
         return nullptr;
@@ -1649,11 +1704,10 @@
 }
 
 int JTuner::setLna(bool enable) {
-    if (mFeClient == nullptr) {
-        ALOGE("frontend client is not initialized");
-        return (int)Result::INVALID_STATE;
+    if (mTunerClient == nullptr) {
+        return (int)Result::NOT_INITIALIZED;
     }
-    Result result = mFeClient->setLna(enable);
+    Result result = mTunerClient->setLna(enable);
     return (int)result;
 }
 
@@ -2519,6 +2573,16 @@
                 env->SetObjectField(statusObj, field, valObj);
                 break;
             }
+            case FrontendStatus::Tag::dvbtCellIds: {
+                jfieldID field = env->GetFieldID(clazz, "mDvbtCellIds", "[I");
+                std::vector<int32_t> ids = s.get<FrontendStatus::Tag::dvbtCellIds>();
+
+                jintArray valObj = env->NewIntArray(v.size());
+                env->SetIntArrayRegion(valObj, 0, v.size(), reinterpret_cast<jint *>(&ids[0]));
+
+                env->SetObjectField(statusObj, field, valObj);
+                break;
+            }
         }
     }
     return statusObj;
@@ -4016,6 +4080,36 @@
     filterClient->freeSharedFilterToken(filterToken);
 }
 
+static jint android_media_tv_Tuner_set_filter_time_delay_hint(
+        JNIEnv *env, jobject filter, int timeDelayInMs) {
+    sp<FilterClient> filterClient = getFilterClient(env, filter);
+    if (filterClient == nullptr) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+                          "Failed to set filter delay: filter client not found");
+    }
+
+    FilterDelayHint delayHint {
+        .hintType = FilterDelayHintType::TIME_DELAY_IN_MS,
+        .hintValue = timeDelayInMs,
+    };
+    return static_cast<jint>(filterClient->setDelayHint(delayHint));
+}
+
+static jint android_media_tv_Tuner_set_filter_data_size_delay_hint(
+        JNIEnv *env, jobject filter, int dataSizeDelayInBytes) {
+    sp<FilterClient> filterClient = getFilterClient(env, filter);
+    if (filterClient == nullptr) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+                          "Failed to set filter delay: filter client not found");
+    }
+
+    FilterDelayHint delayHint {
+        .hintType = FilterDelayHintType::DATA_SIZE_DELAY_IN_BYTES,
+        .hintValue = dataSizeDelayInBytes,
+    };
+    return static_cast<jint>(filterClient->setDelayHint(delayHint));
+}
+
 static sp<TimeFilterClient> getTimeFilterClient(JNIEnv *env, jobject filter) {
     return (TimeFilterClient *)env->GetLongField(filter, gFields.timeFilterContext);
 }
@@ -4195,6 +4289,27 @@
     return filterObj;
 }
 
+static jstring android_media_tv_Tuner_get_frontend_hardware_info(JNIEnv *env, jobject thiz) {
+    sp<JTuner> tuner = getTuner(env, thiz);
+    string info;
+    Result r = tuner->getFrontendHardwareInfo(info);
+    if (r != Result::SUCCESS) {
+        return nullptr;
+    }
+    return env->NewStringUTF(info.data());
+}
+
+static jint android_media_tv_Tuner_set_maximum_frontends(JNIEnv *env, jobject thiz, jint type,
+                                                         jint maxNumber) {
+    sp<JTuner> tuner = getTuner(env, thiz);
+    return tuner->setMaxNumberOfFrontends(type, maxNumber);
+}
+
+static jint android_media_tv_Tuner_get_maximum_frontends(JNIEnv *env, jobject thiz, jint type) {
+    sp<JTuner> tuner = getTuner(env, thiz);
+    return tuner->getMaxNumberOfFrontends(type);
+}
+
 static jint android_media_tv_Tuner_close_frontend(JNIEnv* env, jobject thiz, jint /* handle */) {
     sp<JTuner> tuner = getTuner(env, thiz);
     return tuner->closeFrontend();
@@ -4504,6 +4619,12 @@
     { "nativeOpenSharedFilter",
             "(Ljava/lang/String;)Landroid/media/tv/tuner/filter/SharedFilter;",
             (void *)android_media_tv_Tuner_open_shared_filter},
+    { "nativeGetFrontendHardwareInfo","()Ljava/lang/String;",
+            (void *)android_media_tv_Tuner_get_frontend_hardware_info },
+    { "nativeSetMaxNumberOfFrontends", "(II)I",
+             (void *)android_media_tv_Tuner_set_maximum_frontends },
+    { "nativeGetMaxNumberOfFrontends", "(I)I",
+            (void *)android_media_tv_Tuner_get_maximum_frontends },
 };
 
 static const JNINativeMethod gFilterMethods[] = {
@@ -4524,6 +4645,10 @@
             (void *)android_media_tv_Tuner_acquire_shared_filter_token},
     { "nativeFreeSharedFilterToken", "(Ljava/lang/String;)V",
             (void *)android_media_tv_Tuner_free_shared_filter_token},
+    {"nativeSetTimeDelayHint", "(I)I",
+            (void *)android_media_tv_Tuner_set_filter_time_delay_hint},
+    {"nativeSetDataSizeDelayHint", "(I)I",
+            (void *)android_media_tv_Tuner_set_filter_data_size_delay_hint},
 };
 
 static const JNINativeMethod gSharedFilterMethods[] = {
diff --git a/media/jni/android_media_tv_Tuner.h b/media/jni/android_media_tv_Tuner.h
index 06e2492..f1b31e3 100644
--- a/media/jni/android_media_tv_Tuner.h
+++ b/media/jni/android_media_tv_Tuner.h
@@ -200,6 +200,9 @@
     jint close();
     jint closeFrontend();
     jint closeDemux();
+    Result getFrontendHardwareInfo(string& info);
+    jint setMaxNumberOfFrontends(int32_t frontendType, int32_t maxNumber);
+    int32_t getMaxNumberOfFrontends(int32_t frontendType);
 
     jweak getObject();
 
diff --git a/media/jni/tuner/FrontendClient.cpp b/media/jni/tuner/FrontendClient.cpp
index 70309a0..0fdd8d8 100644
--- a/media/jni/tuner/FrontendClient.cpp
+++ b/media/jni/tuner/FrontendClient.cpp
@@ -102,15 +102,6 @@
     return Result::INVALID_STATE;
 }
 
-Result FrontendClient::setLna(bool bEnable) {
-    if (mTunerFrontend != nullptr) {
-        Status s = mTunerFrontend->setLna(bEnable);
-        return ClientHelper::getServiceSpecificErrorCode(s);
-    }
-
-    return Result::INVALID_STATE;
-}
-
 int32_t FrontendClient::linkCiCamToFrontend(int32_t ciCamId) {
     int32_t ltsId = static_cast<int32_t>(Constant::INVALID_LTS_ID);
 
@@ -143,6 +134,15 @@
     return Result::INVALID_STATE;
 }
 
+Result FrontendClient::getHardwareInfo(string& info) {
+    if (mTunerFrontend != nullptr) {
+        Status s = mTunerFrontend->getHardwareInfo(&info);
+        return ClientHelper::getServiceSpecificErrorCode(s);
+    }
+
+    return Result::INVALID_STATE;
+}
+
 shared_ptr<ITunerFrontend> FrontendClient::getAidlFrontend() {
     return mTunerFrontend;
 }
diff --git a/media/jni/tuner/FrontendClient.h b/media/jni/tuner/FrontendClient.h
index 08c0b20..77d9098 100644
--- a/media/jni/tuner/FrontendClient.h
+++ b/media/jni/tuner/FrontendClient.h
@@ -99,11 +99,6 @@
     Result setLnb(sp<LnbClient> lnbClient);
 
     /**
-     * Enable or Disable Low Noise Amplifier (LNA).
-     */
-    Result setLna(bool bEnable);
-
-    /**
      * Link Frontend to the cicam with given id.
      *
      * @return lts id
@@ -120,7 +115,13 @@
      */
     Result close();
 
+    /**
+     * Get Frontend hardware info.
+     */
+    Result getHardwareInfo(string& info);
+
     int32_t getId();
+
     shared_ptr<ITunerFrontend> getAidlFrontend();
 private:
     /**
diff --git a/media/jni/tuner/TunerClient.cpp b/media/jni/tuner/TunerClient.cpp
index 861d78d..3c8fdfe6 100644
--- a/media/jni/tuner/TunerClient.cpp
+++ b/media/jni/tuner/TunerClient.cpp
@@ -185,4 +185,32 @@
     return nullptr;
 }
 
+Result TunerClient::setLna(bool bEnable) {
+    if (mTunerService != nullptr) {
+        Status s = mTunerService->setLna(bEnable);
+        return ClientHelper::getServiceSpecificErrorCode(s);
+    }
+
+    return Result::INVALID_STATE;
+}
+
+Result TunerClient::setMaxNumberOfFrontends(FrontendType frontendType, int32_t maxNumber) {
+    if (mTunerService != nullptr) {
+        Status s = mTunerService->setMaxNumberOfFrontends(frontendType, maxNumber);
+        return ClientHelper::getServiceSpecificErrorCode(s);
+    }
+
+    return Result::INVALID_STATE;
+}
+
+int TunerClient::getMaxNumberOfFrontends(FrontendType frontendType) {
+    if (mTunerService != nullptr) {
+        int32_t maxNumber;
+        mTunerService->getMaxNumberOfFrontends(frontendType, &maxNumber);
+        return maxNumber;
+    }
+
+    return -1;
+}
+
 }  // namespace android
diff --git a/media/jni/tuner/TunerClient.h b/media/jni/tuner/TunerClient.h
index 3e59e26..a9f37e6 100644
--- a/media/jni/tuner/TunerClient.h
+++ b/media/jni/tuner/TunerClient.h
@@ -32,6 +32,7 @@
 
 using ::aidl::android::hardware::tv::tuner::DemuxCapabilities;
 using ::aidl::android::hardware::tv::tuner::FrontendInfo;
+using ::aidl::android::hardware::tv::tuner::FrontendType;
 using ::aidl::android::hardware::tv::tuner::Result;
 using ::aidl::android::media::tv::tuner::ITunerService;
 
@@ -127,6 +128,26 @@
      */
     sp<FilterClient> openSharedFilter(const string& filterToken, sp<FilterClientCallback> cb);
 
+    /**
+     * Enable or Disable Low Noise Amplifier (LNA).
+     */
+    Result setLna(bool bEnable);
+
+    /**
+     * Set the maximum frontend number of a given frontend type.
+     *
+     * @param frontendType the frontend type which maximum number will be set.
+     * @param maxNumber the new maximum number.
+     */
+    Result setMaxNumberOfFrontends(FrontendType frontendType, int32_t maxNumber);
+
+    /**
+     * Get the maximum frontend number of a given frontend type.
+     *
+     * @param frontendType the frontend type which maximum number will be queried.
+     */
+    int getMaxNumberOfFrontends(FrontendType frontendType);
+
 private:
     /**
      * An AIDL Tuner Service Singleton assigned at the first time the Tuner Client
diff --git a/media/packages/BluetoothMidiService/AndroidManifest.xml b/media/packages/BluetoothMidiService/AndroidManifest.xml
index 03606ba..9039011 100644
--- a/media/packages/BluetoothMidiService/AndroidManifest.xml
+++ b/media/packages/BluetoothMidiService/AndroidManifest.xml
@@ -20,7 +20,7 @@
         xmlns:tools="http://schemas.android.com/tools"
         package="com.android.bluetoothmidiservice"
         >
-    <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29" />
+    <uses-sdk android:minSdkVersion="30" android:targetSdkVersion="30" />
 
     <uses-feature android:name="android.hardware.bluetooth_le"
          android:required="true"/>
diff --git a/media/packages/BluetoothMidiService/AndroidManifestBase.xml b/media/packages/BluetoothMidiService/AndroidManifestBase.xml
index bfb0546..5a900c7 100644
--- a/media/packages/BluetoothMidiService/AndroidManifestBase.xml
+++ b/media/packages/BluetoothMidiService/AndroidManifestBase.xml
@@ -19,7 +19,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="com.android.bluetoothmidiservice"
           >
-    <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29" />
+    <uses-sdk android:minSdkVersion="30" android:targetSdkVersion="30" />
     <application
         android:label="BluetoothMidi"
         android:defaultToDeviceProtectedStorage="true"
diff --git a/omapi/aidl/Android.bp b/omapi/aidl/Android.bp
index 2b81200..d80317b 100644
--- a/omapi/aidl/Android.bp
+++ b/omapi/aidl/Android.bp
@@ -28,8 +28,5 @@
         rust: {
             enabled: true,
         },
-        ndk: {
-            separate_platform_variant: false,
-        },
     },
 }
diff --git a/packages/CompanionDeviceManager/res/layout/activity_confirmation.xml b/packages/CompanionDeviceManager/res/layout/activity_confirmation.xml
index c87bac6..313e164 100644
--- a/packages/CompanionDeviceManager/res/layout/activity_confirmation.xml
+++ b/packages/CompanionDeviceManager/res/layout/activity_confirmation.xml
@@ -14,6 +14,7 @@
      limitations under the License.
 -->
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:id="@+id/activity_confirmation"
               android:layout_width="match_parent"
               android:layout_height="wrap_content"
               android:background="@drawable/dialog_background"
@@ -23,6 +24,8 @@
               android:padding="18dp"
               android:layout_gravity="center">
 
+    <!-- Do NOT change the ID of the root LinearLayout above: it's referenced in CTS tests. -->
+
     <TextView
             android:id="@+id/title"
             android:layout_width="match_parent"
@@ -30,7 +33,6 @@
             android:gravity="center"
             android:paddingHorizontal="12dp"
             style="@*android:style/TextAppearance.Widget.Toolbar.Title"/>
-    <!-- style="@*android:style/TextAppearance.Widget.Toolbar.Title" -->
 
     <TextView
             android:id="@+id/summary"
@@ -61,8 +63,10 @@
             android:orientation="horizontal"
             android:gravity="end">
 
+        <!-- Do NOT change the IDs of the buttons: they are referenced in CTS tests. -->
+
         <Button
-                android:id="@+id/button_cancel"
+                android:id="@+id/btn_negative"
                 style="@android:style/Widget.Material.Button.Borderless.Colored"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
@@ -70,7 +74,7 @@
                 android:textColor="?android:attr/textColorSecondary" />
 
         <Button
-                android:id="@+id/button_allow"
+                android:id="@+id/btn_positive"
                 style="@android:style/Widget.Material.Button.Borderless.Colored"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
diff --git a/packages/CompanionDeviceManager/res/layout/list_item_device.xml b/packages/CompanionDeviceManager/res/layout/list_item_device.xml
new file mode 100644
index 0000000..d79aea6
--- /dev/null
+++ b/packages/CompanionDeviceManager/res/layout/list_item_device.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.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:id="@+id/list_item_device"
+              android:layout_width="match_parent"
+              android:layout_height="wrap_content"
+              android:orientation="horizontal"
+              android:gravity="center_vertical"
+              android:padding="12dp">
+
+    <!-- Do NOT change the ID of the root LinearLayout above: it's referenced in CTS tests. -->
+
+    <ImageView
+            android:id="@android:id/icon"
+            android:layout_width="24dp"
+            android:layout_height="24dp"
+            android:layout_marginRight="12dp"/>
+
+    <TextView
+            android:id="@android:id/text1"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:singleLine="true"
+            android:textAppearance="?android:attr/textAppearanceListItemSmall"/>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/CompanionDeviceManager/res/values-af/strings.xml b/packages/CompanionDeviceManager/res/values-af/strings.xml
index aec8f89..00a5210 100644
--- a/packages/CompanionDeviceManager/res/values-af/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-af/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"Laat &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; toe om jou &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; te bestuur"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"horlosie"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Kies \'n <xliff:g id="PROFILE_NAME">%1$s</xliff:g> om deur &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; bestuur te word"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> sal interaksie met jou kennisgewings mag hê en toegang kry tot jou Foon-, SMS-, Kontakte- en Kalender-toestemmings."</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> sal interaksie met jou kennisgewings mag hê en toegang kry tot jou Foon-, SMS-, Kontakte- en Kalender-toestemmings."</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"Laat &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; toe om programme te stroom?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Gee &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; afstandtoegang tot programme wat op &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; geïnstalleer is wanneer hierdie foon aan die internet gekoppel is."</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Gee &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; afstandtoegang tot programme wat op &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; geïnstalleer is wanneer hierdie tablet aan die internet gekoppel is."</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Gee &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; afstandtoegang tot programme wat op &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; geïnstalleer is wanneer hierdie toestel aan die internet gekoppel is."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"toestel"</string>
diff --git a/packages/CompanionDeviceManager/res/values-am/strings.xml b/packages/CompanionDeviceManager/res/values-am/strings.xml
index 2359124..2254e1f 100644
--- a/packages/CompanionDeviceManager/res/values-am/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-am/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; የእርስዎን <xliff:g id="DEVICE_NAME">%2$s</xliff:g> - &lt;strong&gt;&lt;/strong&gt; እንዲያስተዳደር ይፍቀዱ"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"ሰዓት"</string>
     <string name="chooser_title" msgid="2262294130493605839">"በ&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; የሚተዳደር <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ይምረጡ"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ከማሳወቂያዎችዎ ጋር መስተጋብር እንዲፈጥር እና የእርስዎን ስልክ፣ ኤስኤምኤስ፣ እውቂያዎች እና የቀን መቁጠሪያ ፈቃዶች እንዲደርስ ይፈቀድለታል።"</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ከማሳወቂያዎችዎ ጋር መስተጋብር እንዲፈጥር እና የእርስዎን ስልክ፣ ኤስኤምኤስ፣ እውቂያዎች እና የቀን መቁጠሪያ ፈቃዶች እንዲደርስ ይፈቀድለታል።"</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; መተግበሪያዎችን እንዲለቅቅ ይፈቀድለት?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ሲገናኙ በዚህ ስልክ ላይ የተጫኑ መተግበሪያዎችን እንዲደርስ ለ&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; የርቀት መዳረሻ እንዲያቀርብ ይፍቀዱለት።"</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ሲገናኙ በዚህ ጡባዊ ላይ የተጫኑ መተግበሪያዎችን እንዲደርስ ለ&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; የርቀት መዳረሻ እንዲያቀርብ ይፍቀዱለት።"</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ሲገናኙ በዚህ መሳሪያ ላይ የተጫኑ መተግበሪያዎችን እንዲደርስ ለ&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; የርቀት መዳረሻ እንዲያቀርብ ይፍቀዱለት።"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"መሣሪያ"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ar/strings.xml b/packages/CompanionDeviceManager/res/values-ar/strings.xml
index 5fc3a4f..5944dba3 100644
--- a/packages/CompanionDeviceManager/res/values-ar/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ar/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"‏السماح للتطبيق &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; بإدارة &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"ساعة"</string>
     <string name="chooser_title" msgid="2262294130493605839">"‏اختَر <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ليديره تطبيق &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"سيتم السماح لتطبيق <xliff:g id="APP_NAME">%1$s</xliff:g> بالتفاعل مع الإشعارات والوصول إلى أذونات الهاتف والرسائل القصيرة وجهات الاتصال والتقويم."</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"سيتم السماح لتطبيق <xliff:g id="APP_NAME">%1$s</xliff:g> بالتفاعل مع الإشعارات والوصول إلى أذونات الهاتف والرسائل القصيرة وجهات الاتصال والتقويم."</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"‏هل تريد السماح لتطبيق &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ببث التطبيقات؟"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"‏السماح لتطبيق &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; بمنح الإذن بالوصول عن بُعد إلى التطبيقات المثبَّتة &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; الإذن بالوصول عن بُعد إلى التطبيقات المثبَّتة على هذا الهاتف عندما يكون متصلاً بالإنترنت."</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"‏السماح لتطبيق &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; بمنح &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; الإذن بالوصول عن بُعد إلى التطبيقات المثبَّتة على هذا الجهاز اللوحي عندما يكون متصلاً بالإنترنت."</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"‏السماح لتطبيق &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; بمنح &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; الإذن بالوصول عن بُعد إلى التطبيقات المثبَّتة على هذا الجهاز عندما يكون متصلاً بالإنترنت."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"جهاز"</string>
diff --git a/packages/CompanionDeviceManager/res/values-as/strings.xml b/packages/CompanionDeviceManager/res/values-as/strings.xml
index 743d725..e58aed7 100644
--- a/packages/CompanionDeviceManager/res/values-as/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-as/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ক আপোনাৰ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; পৰিচালনা কৰিবলৈ দিয়ক"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"ঘড়ী"</string>
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;এ পৰিচালনা কৰিব লগা এটা <xliff:g id="PROFILE_NAME">%1$s</xliff:g> বাছনি কৰক"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g>ক আপোনাৰ জাননী ব্যৱহাৰ কৰিবলৈ আৰু আপোনাৰ ফ’ন, এছএমএছ, সম্পৰ্ক আৰু কেলেণ্ডাৰৰ অনুমতি এক্সেছ কৰিবলৈ দিয়া হ’ব।"</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g>ক আপোনাৰ জাননী ব্যৱহাৰ কৰিবলৈ আৰু আপোনাৰ ফ’ন, এছএমএছ, সম্পৰ্ক আৰু কেলেণ্ডাৰৰ অনুমতি এক্সেছ কৰিবলৈ দিয়া হ’ব।"</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ক এপ্লিকেশ্বন ষ্ট্ৰীম কৰিবলৈ অনুমতি দিবনে?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"সংযোগ কৰিলে &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ক এই ফ’নটোত ইনষ্টল কৰি থোৱা এপ্লিকেশ্বনসমূহ এক্সেছ কৰিবলৈ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;ক ৰিম’ট এক্সেছ দিবলৈ দিয়ক।"</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"সংযোগ কৰিলে &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ক এই টেবলেটটোত ইনষ্টল কৰি থোৱা এপ্লিকেশ্বনসমূহ এক্সেছ কৰিবলৈ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;ক ৰিম’ট এক্সেছ দিবলৈ দিয়ক।"</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"সংযোগ কৰিলে &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ক এই ডিভাইচটোত ইনষ্টল কৰি থোৱা এপ্লিকেশ্বনসমূহ এক্সেছ কৰিবলৈ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;ক ৰিম’ট এক্সেছ দিবলৈ দিয়ক।"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"ডিভাইচ"</string>
diff --git a/packages/CompanionDeviceManager/res/values-az/strings.xml b/packages/CompanionDeviceManager/res/values-az/strings.xml
index ca32052..7577776 100644
--- a/packages/CompanionDeviceManager/res/values-az/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-az/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tətbiqinə &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; cihazınızı idarə etməsinə icazə verin"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"izləyin"</string>
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; tərəfindən idarə ediləcək <xliff:g id="PROFILE_NAME">%1$s</xliff:g> seçin"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> bildirişlərinizə, Telefon, SMS, Kontaktlar və Təqvimə giriş əldə edəcək."</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> bildirişlərinizə, Telefon, SMS, Kontaktlar və Təqvimə giriş əldə edəcək."</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tətbiqinin tətbiqlərdə yayım etməsinə icazə verilsin?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tətbiqinə &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; cihazının qoşulduqda bu telefonda quraşdırılmış tətbiqlərə uzaqdan giriş icazəsi verməsinə imkan verin."</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tətbiqinə &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; cihazının qoşulduqda bu planşetdə quraşdırılmış tətbiqlərə uzaqdan giriş icazəsi verməsinə imkan verin."</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tətbiqinə &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; cihazının qoşulduqda bu cihazda quraşdırılmış tətbiqlərə uzaqdan giriş icazəsi verməsinə imkan verin."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"cihaz"</string>
diff --git a/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml b/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml
index d919e67..8a63b11 100644
--- a/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"Dozvolite aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da upravlja uređajem &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"sat"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Odaberite profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g> kojim će upravljati aplikacija &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> će dobiti dozvolu za interakciju sa obaveštenjima i pristup dozvolama za telefon, SMS poruke, kontakte i kalendar."</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> će dobiti dozvolu za interakciju sa obaveštenjima i pristup dozvolama za telefon, SMS poruke, kontakte i kalendar."</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"Želite da dozvolite aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da strimuje aplikacije?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Dozvolite aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da daljinski pristupa aplikacijama instaliranim na telefonu &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; kada je povezan."</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Dozvolite aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da daljinski pristupa aplikacijama instaliranim na tabletu &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; kada je povezan."</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Dozvolite aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da daljinski pristupa aplikacijama instaliranim na uređaju &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; kada je povezan."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"uređaj"</string>
diff --git a/packages/CompanionDeviceManager/res/values-be/strings.xml b/packages/CompanionDeviceManager/res/values-be/strings.xml
index 919d729..bf4fe3e 100644
--- a/packages/CompanionDeviceManager/res/values-be/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-be/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"Дазвольце праграме &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; кіраваць прыладай &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"гадзіннік"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Выберыце прыладу (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>), якой будзе кіраваць праграма &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> атрымае доступ да вашых апавяшчэнняў, тэлефона, SMS, кантактаў і календара."</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> атрымае доступ да вашых апавяшчэнняў, тэлефона, SMS, кантактаў і календара."</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"Дазволіць праграме &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; перадаваць праграмы плынню?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Дазвольце праграме &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; атрымліваць аддалены доступ да праграм, усталяваных на тэлефоне &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; (калі тэлефон падключаны)."</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Дазвольце праграме &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; атрымліваць аддалены доступ да праграм, усталяваных на планшэце &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; (калі планшэт падключаны)."</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Дазвольце праграме &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; атрымліваць аддалены доступ да праграм, усталяваных на прыладзе &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; (калі прылада падключана)."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"прылада"</string>
diff --git a/packages/CompanionDeviceManager/res/values-bg/strings.xml b/packages/CompanionDeviceManager/res/values-bg/strings.xml
index 1e2aa4e..cc67b13 100644
--- a/packages/CompanionDeviceManager/res/values-bg/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-bg/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"Разрешаване на &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да управлява устройството ви &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"часовник"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Изберете устройство (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>), което да се управлява от &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ще получи разрешение да взаимодейства с известията ви и да осъществява достъп до разрешенията за телефона, SMS съобщенията, контактите и календара."</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ще получи разрешение да взаимодейства с известията ви и да осъществява достъп до разрешенията за телефона, SMS съобщенията, контактите и календара."</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"Разрешавате ли на &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да предава поточно приложения?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Разрешете на &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да предоставя на &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; отдалечен достъп до приложенията, инсталирани на този телефон, когато има установена връзка."</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Разрешете на &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да предоставя на &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; отдалечен достъп до приложенията, инсталирани на този таблет, когато има установена връзка."</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Разрешете на &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да предоставя на &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; отдалечен достъп до приложенията, инсталирани на това устройство, когато има установена връзка."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"устройство"</string>
diff --git a/packages/CompanionDeviceManager/res/values-bn/strings.xml b/packages/CompanionDeviceManager/res/values-bn/strings.xml
index 3b537b6..08ffab0 100644
--- a/packages/CompanionDeviceManager/res/values-bn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-bn/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"আপনার &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ম্যানেজ করার জন্য &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; -কে অনুমতি দিন"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"ঘড়ি"</string>
     <string name="chooser_title" msgid="2262294130493605839">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g> বেছে নিন যেটি &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; ম্যানেজ করবে"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> আপনার বিজ্ঞপ্তির সাথে ইন্টার‌্যাক্ট করতে পারবে, তার সাথে আপনার ফোন, এমএসএস, পরিচিতি এবং ক্যালেন্ডারের অনুমতিও অ্যাক্সেস করতে পারবে।"</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> আপনার বিজ্ঞপ্তির সাথে ইন্টার‌্যাক্ট করতে পারবে, তার সাথে আপনার ফোন, এমএসএস, পরিচিতি এবং ক্যালেন্ডারের অনুমতিও অ্যাক্সেস করতে পারবে।"</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"অ্যাপ্লিকেশন স্ট্রিম করার জন্য &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; কে অনুমতি দেবেন?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; কে &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;এ দূরবর্তী অ্যাক্সেস প্রদান করতে দিন যাতে কানেক্ট থাকাকালীন এই ফোনে ইনস্টল করা অ্যাপ্লিকেশনগুলিতে অ্যাক্সেস করা যায়।"</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; কে &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;এ দূরবর্তী অ্যাক্সেস প্রদান করতে দিন যাতে কানেক্ট থাকাকালীন এই ট্যাবলেটে ইনস্টল করা অ্যাপ্লিকেশনগুলিতে অ্যাক্সেস করা যায়।"</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; কে &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;এ দূরবর্তী অ্যাক্সেস প্রদান করতে দিন যাতে কানেক্ট থাকাকালীন এই ডিভাইসে ইনস্টল করা অ্যাপ্লিকেশনগুলিতে অ্যাক্সেস করা যায়।"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"ডিভাইস"</string>
diff --git a/packages/CompanionDeviceManager/res/values-bs/strings.xml b/packages/CompanionDeviceManager/res/values-bs/strings.xml
index b010626..8b0daaa 100644
--- a/packages/CompanionDeviceManager/res/values-bs/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-bs/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"Dozvolite aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da upravlja uređajem &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"sat"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Odaberite uređaj <xliff:g id="PROFILE_NAME">%1$s</xliff:g> kojim će upravljati aplikacija &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"Aplikaciji <xliff:g id="APP_NAME">%1$s</xliff:g> će se dozvoliti da ostvari interakciju s vašim obavještenjima i da pristupi odobrenjima za Telefon, SMS, Kontakte i Kalendar."</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"Aplikaciji <xliff:g id="APP_NAME">%1$s</xliff:g> će se dozvoliti da ostvari interakciju s vašim obavještenjima i da pristupi odobrenjima za Telefon, SMS, Kontakte i Kalendar."</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"Dozvoliti da &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; prenosi aplikacije?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Dozvolite da &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; omogući daljinski pristup uređaju &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; radi pristupanja aplikacijama instaliranim na ovom telefonu kada je povezan s mrežom."</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Dozvolite da &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; omogući daljinski pristup uređaju &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; radi pristupanja aplikacijama instaliranim na ovom tabletu kada je povezan s mrežom."</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Dozvolite da &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; omogući daljinski pristup uređaju &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; radi pristupanja aplikacijama instaliranim na njemu kada je povezan s mrežom."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"uređaj"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ca/strings.xml b/packages/CompanionDeviceManager/res/values-ca/strings.xml
index efd801e..c98feb3 100644
--- a/packages/CompanionDeviceManager/res/values-ca/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ca/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"Permet que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; gestioni el teu &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"rellotge"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Tria un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> perquè el gestioni &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> tindrà permís per interaccionar amb les teves notificacions i accedir al telèfon, als SMS, als contactes i al calendari."</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> tindrà permís per interaccionar amb les teves notificacions i accedir al telèfon, als SMS, als contactes i al calendari."</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"Vols permetre que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; reprodueixi aplicacions en continu?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Permet que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; proporcioni accés remot a &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; per accedir a les aplicacions instal·lades en aquest telèfon quan estigui connectat."</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Permet que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; proporcioni accés remot a &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; per accedir a les aplicacions instal·lades en aquesta tauleta quan estigui connectada."</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Permet que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; proporcioni accés remot a &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; per accedir a les aplicacions instal·lades en aquest dispositiu quan estigui connectat."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"dispositiu"</string>
diff --git a/packages/CompanionDeviceManager/res/values-cs/strings.xml b/packages/CompanionDeviceManager/res/values-cs/strings.xml
index bd57213..c758b6e 100644
--- a/packages/CompanionDeviceManager/res/values-cs/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-cs/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"Povolit aplikaci &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; spravovat &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"hodinky"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Vyberte zařízení <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, které chcete spravovat pomocí aplikace &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> bude moci interagovat s vašimi oznámeními a získá přístup k telefonu, SMS, kontaktům a kalendáři."</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> bude moci interagovat s vašimi oznámeními a získá přístup k telefonu, SMS, kontaktům a kalendáři."</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"Povolit aplikaci &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; streamovat aplikace?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Povolit aplikaci &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; poskytovat &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; vzdálený přístup k aplikacím nainstalovaným v tomto telefonu, když je připojen."</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Povolit aplikaci &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; poskytovat &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; vzdálený přístup k aplikacím nainstalovaným v tomto tabletu, když je připojen."</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Povolit aplikaci &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; poskytovat &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; vzdálený přístup k aplikacím nainstalovaným v tomto zařízení, když je připojeno."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"zařízení"</string>
diff --git a/packages/CompanionDeviceManager/res/values-da/strings.xml b/packages/CompanionDeviceManager/res/values-da/strings.xml
index 7428453..b026bb1 100644
--- a/packages/CompanionDeviceManager/res/values-da/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-da/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"Tillad at &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; kan administrere: &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"ur"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Vælg den enhed (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>), som skal administreres af &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> får tilladelse til at interagere med dine notifikationer og adgang til dine tilladelser for Opkald, Sms, Kontakter og Kalender."</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> får tilladelse til at interagere med dine notifikationer og adgang til dine tilladelser for Opkald, Sms, Kontakter og Kalender."</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"Vil du give &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tilladelse til at streame apps?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Giver &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tilladelse til at fjernstyre apps, som er installeret på &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;, når telefonen har forbindelse til internettet."</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Giver &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tilladelse til at fjernstyre apps, som er installeret på &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;, når tabletten har forbindelse til internettet."</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Giver &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tilladelse til at fjernstyre apps, som er installeret på &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;, når enheden har forbindelse til internettet."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"enhed"</string>
diff --git a/packages/CompanionDeviceManager/res/values-de/strings.xml b/packages/CompanionDeviceManager/res/values-de/strings.xml
index 4c43140..345b971 100644
--- a/packages/CompanionDeviceManager/res/values-de/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-de/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; erlauben, dein Gerät &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; zu verwalten"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"Smartwatch"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Gerät (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>) auswählen, das von &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; verwaltet werden soll"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> darf mit deinen Benachrichtigungen interagieren und auf die Berechtigungen „Telefon“, „SMS“, „Kontakte“ und „Kalender“ zugreifen."</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> darf mit deinen Benachrichtigungen interagieren und auf die Berechtigungen „Telefon“, „SMS“, „Kontakte“ und „Kalender“ zugreifen."</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"Möchtest du &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; erlauben, Apps zu streamen?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Besteht eine Verbindung, darf &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; Remotezugriff auf die auf diesem Smartphone installierten Apps geben."</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Besteht eine Verbindung, darf &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; Remotezugriff auf die auf diesem Tablet installierten Apps geben."</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Besteht eine Verbindung, darf &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; Remotezugriff auf die auf diesem Gerät installierten Apps geben."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"Gerät"</string>
diff --git a/packages/CompanionDeviceManager/res/values-el/strings.xml b/packages/CompanionDeviceManager/res/values-el/strings.xml
index 07a4fda..64d500e 100644
--- a/packages/CompanionDeviceManager/res/values-el/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-el/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"Επιτρέψτε στην εφαρμογή &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; να διαχειρίζεται τη συσκευή &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"ρολόι"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Επιλέξτε ένα προφίλ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> για διαχείριση από την εφαρμογή &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> θα επιτρέπεται να αλληλεπιδρά με τις ειδοποιήσεις σας και να έχει πρόσβαση στις άδειες Τηλεφώνου, SMS, Επαφών και Ημερολογίου."</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> θα επιτρέπεται να αλληλεπιδρά με τις ειδοποιήσεις σας και να έχει πρόσβαση στις άδειες Τηλεφώνου, SMS, Επαφών και Ημερολογίου."</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"Να επιτρέπεται στην εφαρμογή &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; η ροή εφαρμογών;"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Επιτρέψτε στην εφαρμογή &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; να παρέχει απομακρυσμένη πρόσβαση στη συσκευή &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; κατά τη σύνδεση, προκειμένου να έχει πρόσβαση σε εφαρμογές που έχουν εγκατασταθεί σε αυτό το τηλέφωνο."</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Επιτρέψτε στην εφαρμογή &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; να παρέχει απομακρυσμένη πρόσβαση στη συσκευή &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; κατά τη σύνδεση, προκειμένου να έχει πρόσβαση σε εφαρμογές που έχουν εγκατασταθεί σε αυτό το tablet."</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Επιτρέψτε στην εφαρμογή &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; να παρέχει απομακρυσμένη πρόσβαση στη συσκευή &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; κατά τη σύνδεση, προκειμένου να έχει πρόσβαση σε εφαρμογές που έχουν εγκατασταθεί σε αυτήν τη συσκευή."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"συσκευή"</string>
diff --git a/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml b/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml
index 9bbc1b8..90e33a5 100644
--- a/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"Permite que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; administre tu &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"reloj"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Elige un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para que &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; lo administre"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> podrá interactuar con tus notificaciones y acceder a los permisos de Teléfono, SMS, Contactos y Calendario."</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> podrá interactuar con tus notificaciones y acceder a los permisos de Teléfono, SMS, Contactos y Calendario."</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"¿Deseas permitir que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; transmita aplicaciones?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Permite que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; proporcione a &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; acceso remoto a las aplicaciones instaladas en este teléfono cuando esté conectado."</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Permite que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; proporcione &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; acceso remoto a las aplicaciones instaladas en esta tablet cuando esté conectada."</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Permite que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; proporcione a &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; acceso remoto a las aplicaciones instaladas en este dispositivo cuando esté conectado."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
diff --git a/packages/CompanionDeviceManager/res/values-es/strings.xml b/packages/CompanionDeviceManager/res/values-es/strings.xml
index daece56..78ac63f 100644
--- a/packages/CompanionDeviceManager/res/values-es/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-es/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"Permitir que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; gestione tu &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"reloj"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Elige un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para gestionarlo con &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> podrá interactuar con tus notificaciones y acceder a tus permisos de teléfono, SMS, contactos y calendario."</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> podrá interactuar con tus notificaciones y acceder a tus permisos de teléfono, SMS, contactos y calendario."</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"¿Permitir que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; inicie aplicaciones?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Permite que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acceda de forma remota a las aplicaciones instaladas en este teléfono cuando &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; esté conectado a Internet."</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Permite que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acceda de forma remota a las aplicaciones instaladas en este tablet cuando &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; esté conectado a Internet."</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Permite que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acceda de forma remota a las aplicaciones instaladas en este dispositivo cuando &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; esté conectado a Internet."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
diff --git a/packages/CompanionDeviceManager/res/values-et/strings.xml b/packages/CompanionDeviceManager/res/values-et/strings.xml
index ffaa0c0..165dc97 100644
--- a/packages/CompanionDeviceManager/res/values-et/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-et/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"Lubage rakendusel &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; hallata teie seadet &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"käekell"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Valige seade <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, mida haldab rakendus &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> saab kasutada teie märguandeid ning pääseda juurde teie telefoni, SMS-ide, kontaktide ja kalendri lubadele."</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> saab kasutada teie märguandeid ning pääseda juurde teie telefoni, SMS-ide, kontaktide ja kalendri lubadele."</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"Kas lubada rakendusel &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; rakendusi voogesituse kaudu üle kanda?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Rakendusel &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; lubatakse seadmele &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; pakkuda kaugjuurdepääsu, et ühendatuna pääseda juurde sellesse telefoni installitud rakendustele."</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Rakendusel &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; lubatakse seadmele &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; pakkuda kaugjuurdepääsu, et ühendatuna pääseda juurde sellesse tahvelarvutisse installitud rakendustele."</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Rakendusel &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; lubatakse seadmele &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; pakkuda kaugjuurdepääsu, et ühendatuna pääseda juurde sellesse seadmesse installitud rakendustele."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"seade"</string>
diff --git a/packages/CompanionDeviceManager/res/values-eu/strings.xml b/packages/CompanionDeviceManager/res/values-eu/strings.xml
index 5bf6677..377e0c3 100644
--- a/packages/CompanionDeviceManager/res/values-eu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-eu/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"Eman &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; kudeatzeko baimena &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; aplikazioari"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"erlojua"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Aukeratu &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; aplikazioak kudeatu beharreko <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"Jakinarazpenekin interakzioan aritzeko eta telefonoa, SMSak, kontaktuak eta egutegia erabiltzeko baimena izango du <xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak."</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"Jakinarazpenekin interakzioan aritzeko eta telefonoa, SMSak, kontaktuak eta egutegia erabiltzeko baimena izango du <xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak."</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"Aplikazioak igortzeko baimena eman nahi diozu &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; aplikazioari?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Utzi &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; aplikazioari &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; urrunetik atzitzen, telefonoa konektatuta dagoenean bertan instalatuta dauden aplikazioetarako sarbidea izateko."</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Utzi &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; aplikazioari &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; urrunetik atzitzen, tableta konektatuta dagoenean bertan instalatuta dauden aplikazioetarako sarbidea izateko."</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Utzi &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; aplikazioari &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; urrunetik atzitzen, gailua konektatuta dagoenean bertan instalatuta dauden aplikazioetarako sarbidea izateko."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"gailua"</string>
diff --git a/packages/CompanionDeviceManager/res/values-fa/strings.xml b/packages/CompanionDeviceManager/res/values-fa/strings.xml
index 1ede28c..d9053fd 100644
--- a/packages/CompanionDeviceManager/res/values-fa/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fa/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"‏مجاز کردن &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; برای مدیریت کردن &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"ساعت"</string>
     <string name="chooser_title" msgid="2262294130493605839">"‏انتخاب <xliff:g id="PROFILE_NAME">%1$s</xliff:g> برای مدیریت کردن با &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>‏&lt;/strong&gt;"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> می‌تواند با اعلان‌های شما تعامل داشته باشد و به اجازه‌های «تلفن»، «پیامک»، «مخاطبین»، و «تقویم» دسترسی پیدا کند."</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> می‌تواند با اعلان‌های شما تعامل داشته باشد و به اجازه‌های «تلفن»، «پیامک»، «مخاطبین»، و «تقویم» دسترسی پیدا کند."</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"‏به &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; اجازه می‌دهید برنامه‌ها را جاری‌سازی کند؟"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"‏به &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; اجازه می‌دهد برای &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; دسترسی ازراه‌دور ارائه دهد تا دستگاه موردنظر بتواند هنگام اتصال، به برنامه‌های نصب‌شده در این تلفن دسترسی داشته باشد."</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"‏به &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; اجازه می‌دهد برای &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; دسترسی ازراه‌دور ارائه دهد تا دستگاه موردنظر بتواند هنگام اتصال، به برنامه‌های نصب‌شده در این رایانه لوحی دسترسی داشته باشد."</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"‏به &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; اجازه می‌دهد برای &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; دسترسی ازراه‌دور ارائه دهد تا دستگاه موردنظر بتواند هنگام اتصال، به برنامه‌های نصب‌شده در این دستگاه دسترسی داشته باشد."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"دستگاه"</string>
diff --git a/packages/CompanionDeviceManager/res/values-fi/strings.xml b/packages/CompanionDeviceManager/res/values-fi/strings.xml
index ac948df..e76f89d 100644
--- a/packages/CompanionDeviceManager/res/values-fi/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fi/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"Salli, että &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; voi hallinnoida tätä laitettasi: &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"kello"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Valitse <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, jota &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; hallinnoi"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> saa luvan hallinnoida ilmoituksiasi sekä pääsyn puhelimeesi, tekstiviesteihisi, kontakteihisi ja kalenteriisi."</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> saa luvan hallinnoida ilmoituksiasi sekä pääsyn puhelimeesi, tekstiviesteihisi, kontakteihisi ja kalenteriisi."</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"Saako &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; striimata sovelluksia?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Salli, että &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; voi saada sovellukselta (&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>) etäpääsyoikeuden tälle puhelimelle asennettuihin sovelluksiin, kun laitteet on yhdistetty."</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Salli, että &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; voi saada sovellukselta (&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>) etäpääsyoikeuden tälle tabletille asennettuihin sovelluksiin, kun laitteet on yhdistetty."</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Salli, että &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; voi saada sovellukselta (&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>) etäpääsyoikeuden tälle laitteelle asennettuihin sovelluksiin, kun laitteet on yhdistetty."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"laite"</string>
diff --git a/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml b/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml
index 19f97f0..f6a4855 100644
--- a/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"Autoriser &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; à gérer votre &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"montre"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Choisissez un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> qui sera géré par &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> aura l\'autorisation d\'interagir avec vos notifications et d\'accéder aux autorisations pour votre téléphone, vos messages texte, vos contacts et votre agenda."</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> aura l\'autorisation d\'interagir avec vos notifications et d\'accéder aux autorisations pour votre téléphone, vos messages texte, vos contacts et votre agenda."</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"Permettre à l\'application &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; de diffuser des applications?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Permettez à l\'application &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; de donner à l\'appareil &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; un accès à distance aux applications installées sur ce téléphone lorsqu\'il est connecté."</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Permettez à l\'application &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; de donner à l\'appareil &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; un accès à distance aux applications installées sur cette tablette lorsqu\'elle est connectée."</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Permettez à l\'application &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; de donner à l\'appareil &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; un accès à distance aux applications installées sur cet appareil lorsqu\'il est connecté."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"appareil"</string>
diff --git a/packages/CompanionDeviceManager/res/values-fr/strings.xml b/packages/CompanionDeviceManager/res/values-fr/strings.xml
index 8a7ae1a..a214b89 100644
--- a/packages/CompanionDeviceManager/res/values-fr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fr/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"Autoriser &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; à gérer votre &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"montre"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Sélectionner le/la <xliff:g id="PROFILE_NAME">%1$s</xliff:g> qui sera géré(e) par &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> aura l\'autorisation d\'interagir avec vos notifications et d\'accéder au téléphone, aux SMS, aux contacts et à l\'agenda."</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> aura l\'autorisation d\'interagir avec vos notifications et d\'accéder au téléphone, aux SMS, aux contacts et à l\'agenda."</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"Autoriser &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; à diffuser des applis en streaming ?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Autoriser &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; à accéder à distance aux applis installées sur &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; quand ce téléphone est connecté à Internet."</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Autoriser &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; à accéder à distance aux applis installées sur &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; quand cette tablette est connectée à Internet."</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Autoriser &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; à accéder à distance aux applis installées sur &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; quand cet appareil est connecté à Internet."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"appareil"</string>
diff --git a/packages/CompanionDeviceManager/res/values-gl/strings.xml b/packages/CompanionDeviceManager/res/values-gl/strings.xml
index 052c207..c179378 100644
--- a/packages/CompanionDeviceManager/res/values-gl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-gl/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"Permitir que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; xestione o teu dispositivo (&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;)"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"reloxo"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Escolle un perfil (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>) para que o xestione a aplicación &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> poderá interactuar coas túas notificacións e acceder aos permisos do teu teléfono, das mensaxes, dos contactos e do calendario."</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> poderá interactuar coas túas notificacións e acceder aos permisos do teu teléfono, das mensaxes, dos contactos e do calendario."</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"Queres permitir que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; emita aplicacións noutros dispositivos?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Permite que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; lle outorgue a &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; acceso remoto a aplicacións instaladas neste teléfono cando teña conexión a Internet."</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Permite que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; lle outorgue a &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; acceso remoto a aplicacións instaladas nesta tableta cando teña conexión a Internet."</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Permite que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; lle outorgue a &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; acceso remoto a aplicacións instaladas neste dispositivo cando teña conexión a Internet."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
diff --git a/packages/CompanionDeviceManager/res/values-gu/strings.xml b/packages/CompanionDeviceManager/res/values-gu/strings.xml
index 279de16..ff9a89e 100644
--- a/packages/CompanionDeviceManager/res/values-gu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-gu/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"તમારા &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;ને મેનેજ કરવા માટે &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ને મંજૂર કરો"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"સ્માર્ટવૉચ"</string>
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; દ્વારા મેનેજ કરવા માટે કોઈ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> પસંદ કરો"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g>ને તમારા નોટિફિકેશન સાથે ક્રિયાપ્રતિક્રિયા કરવાની તેમજ તમારો ફોન, SMS, સંપર્કો તેમજ કૅલેન્ડરની પરવાનગીઓ ઍક્સેસ કરવાની મંજૂરી આપવામાં આવશે."</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g>ને તમારા નોટિફિકેશન સાથે ક્રિયાપ્રતિક્રિયા કરવાની તેમજ તમારો ફોન, SMS, સંપર્કો તેમજ કૅલેન્ડરની પરવાનગીઓ ઍક્સેસ કરવાની મંજૂરી આપવામાં આવશે."</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"શું &lt;/strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ને ઍપ્લિકેશનો સ્ટ્રીમ કરવાની મંજૂરી આપીએ?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"જ્યારે કનેક્ટ કરવામાં આવે, ત્યારે આ ફોન પર ઇન્સ્ટૉલ કરવામાં આવેલી ઍપ્લિકેશનોનો રિમોટ ઍક્સેસ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ને &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;ને પ્રદાન કરવા દો."</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"જ્યારે કનેક્ટ કરવામાં આવે, ત્યારે આ ટૅબ્લેટ પર ઇન્સ્ટૉલ કરવામાં આવેલી ઍપ્લિકેશનોનો રિમોટ ઍક્સેસ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ને &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;ને પ્રદાન કરવા દો."</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"જ્યારે કનેક્ટ કરવામાં આવે, ત્યારે આ ડિવાઇસ પર ઇન્સ્ટૉલ કરવામાં આવેલી ઍપ્લિકેશનોનો રિમોટ ઍક્સેસ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ને &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;ને પ્રદાન કરવા દો."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"ડિવાઇસ"</string>
diff --git a/packages/CompanionDeviceManager/res/values-hi/strings.xml b/packages/CompanionDeviceManager/res/values-hi/strings.xml
index 7704829..557e1f8 100644
--- a/packages/CompanionDeviceManager/res/values-hi/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hi/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; को, अपनी &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; मैनेज करने की अनुमति दें"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"स्मार्टवॉच"</string>
     <string name="chooser_title" msgid="2262294130493605839">"कोई <xliff:g id="PROFILE_NAME">%1$s</xliff:g> चुनें, ताकि उसे &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; की मदद से प्रबंधित किया जा सके"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> आपकी सूचनाओं पर कार्रवाई कर पाएगा. साथ ही, यह आपके फ़ोन, एसएमएस, संपर्कों, और कैलेंडर की अनुमतियों को भी ऐक्सेस कर पाएगा."</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> आपकी सूचनाओं पर कार्रवाई कर पाएगा. साथ ही, यह आपके फ़ोन, एसएमएस, संपर्कों, और कैलेंडर की अनुमतियों को भी ऐक्सेस कर पाएगा."</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; को ऐप्लिकेशन स्ट्रीम करने की अनुमति देनी है?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"कनेक्ट होने पर, &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; को &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; के रिमोट ऐक्सेस की अनुमति दें, ताकि इस फ़ोन पर इंस्टॉल किए गए ऐप्लिकेशन ऐक्सेस किए जा सकें."</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"कनेक्ट होने पर, &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; को &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; के रिमोट ऐक्सेस की अनुमति दें, ताकि इस टैबलेट पर इंस्टॉल किए गए ऐप्लिकेशन ऐक्सेस किए जा सकें."</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"कनेक्ट होने पर, &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; को &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; के रिमोट ऐक्सेस की अनुमति दें, ताकि इस डिवाइस पर इंस्टॉल किए गए ऐप्लिकेशन ऐक्सेस किए जा सकें."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"डिवाइस"</string>
diff --git a/packages/CompanionDeviceManager/res/values-hr/strings.xml b/packages/CompanionDeviceManager/res/values-hr/strings.xml
index e7db2ba..453a4dd 100644
--- a/packages/CompanionDeviceManager/res/values-hr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hr/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"Dopustite aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da upravlja vašim &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"satom"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Odaberite profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g> kojim će upravljati aplikacija &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> moći će stupati u interakciju s vašim obavijestima i pristupati dopuštenjima za telefon, SMS-ove, kontakte i kalendar."</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> moći će stupati u interakciju s vašim obavijestima i pristupati dopuštenjima za telefon, SMS-ove, kontakte i kalendar."</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"Dopustiti aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; pokretanje streama aplikacija?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Dopustite aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da telefonu &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; omogući udaljeni pristup aplikacijama koje su instalirane na tom telefonu kada su povezani."</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Dopustite aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da tabletu &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; omogući udaljeni pristup aplikacijama koje su instalirane na tom tabletu kada su povezani."</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Dopustite aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da uređaju &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; omogući udaljeni pristup aplikacijama koje su instalirane na tom uređaju kada su povezani."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"uređaj"</string>
diff --git a/packages/CompanionDeviceManager/res/values-hu/strings.xml b/packages/CompanionDeviceManager/res/values-hu/strings.xml
index 56f02a5..dacc4e4 100644
--- a/packages/CompanionDeviceManager/res/values-hu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hu/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"A(z) &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; engedélyezése a(z) &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; kezelésére"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"óra"</string>
     <string name="chooser_title" msgid="2262294130493605839">"A(z) &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; alkalmazással kezelni kívánt <xliff:g id="PROFILE_NAME">%1$s</xliff:g> kiválasztása"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> műveleteket végezhet majd az értesítésekkel, és hozzáférhet a telefonra, az SMS-ekre, a névjegyekre és a naptárra vonatkozó engedélyekhez."</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> műveleteket végezhet majd az értesítésekkel, és hozzáférhet a telefonra, az SMS-ekre, a névjegyekre és a naptárra vonatkozó engedélyekhez."</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"Engedélyezi a(z) &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; alkalmazásnak appok streamelését?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Engedélyezheti a(z) &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; alkalmazásnak, hogy a(z) &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; eszköz számára távoli hozzáférést biztosítson a telefonra telepített alkalmazásokhoz, amikor a telefon csatlakoztatva van."</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Engedélyezheti a(z) &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; alkalmazásnak, hogy a(z) &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; eszköz számára távoli hozzáférést biztosítson a táblagépre telepített alkalmazásokhoz, amikor a táblagép csatlakoztatva van."</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Engedélyezheti a(z) &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; alkalmazásnak, hogy a(z) &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; eszköz számára távoli hozzáférést biztosítson az eszközre telepített alkalmazásokhoz, amikor az eszköz csatlakoztatva van."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"eszköz"</string>
diff --git a/packages/CompanionDeviceManager/res/values-hy/strings.xml b/packages/CompanionDeviceManager/res/values-hy/strings.xml
index cf22fbc..9b79f4b 100644
--- a/packages/CompanionDeviceManager/res/values-hy/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hy/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"Թույլատրեք &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; հավելվածին կառավարել ձեր &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; սարքը"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"ժամացույց"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Ընտրեք <xliff:g id="PROFILE_NAME">%1$s</xliff:g>ը, որը պետք է կառավարվի &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; հավելվածի կողմից"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը կկարողանա փոխազդել ձեր ծանուցումների հետ և կստանա «Հեռախոս», «SMS», «Կոնտակտներ» և «Օրացույց» ծառայությունների թույլտվությունները։"</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը կկարողանա փոխազդել ձեր ծանուցումների հետ և կստանա «Հեռախոս», «SMS», «Կոնտակտներ» և «Օրացույց» ծառայությունների թույլտվությունները։"</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"Թույլատրե՞լ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; հավելվածին բացել հավելվածներ"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Թույլ տվեք, որ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; հավելվածը կապի հաստատման դեպքում &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;-ին տրամադրի այս հեռախոսում տեղադրված հավելվածներ հեռակա մուտք գործելու թույլտվություն։"</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Թույլ տվեք, որ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; հավելվածը կապի հաստատման դեպքում &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;-ին տրամադրի այս պլանշետում տեղադրված հավելվածներ հեռակա մուտք գործելու թույլտվություն։"</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Թույլ տվեք, որ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; հավելվածը ինտերնետ կապի հաստատման դեպքում &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;-ին տրամադրի այս սարքում տեղադրված հավելվածներ հեռակա մուտք գործելու թույլտվություն։"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"սարք"</string>
diff --git a/packages/CompanionDeviceManager/res/values-in/strings.xml b/packages/CompanionDeviceManager/res/values-in/strings.xml
index 41f1d09..684167e 100644
--- a/packages/CompanionDeviceManager/res/values-in/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-in/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"Izinkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; untuk mengelola &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"smartwatch"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Pilih <xliff:g id="PROFILE_NAME">%1$s</xliff:g> untuk dikelola oleh &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> akan diizinkan berinteraksi dengan notifikasi dan mengakses izin Telepon, SMS, Kontak, dan Kalender."</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> akan diizinkan berinteraksi dengan notifikasi dan mengakses izin Telepon, SMS, Kontak, dan Kalender."</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"Izinkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; men-streaming aplikasi?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Izinkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; memberikan akses jarak jauh ke &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; guna mengakses aplikasi yang diinstal di ponsel ini saat terhubung."</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Izinkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; memberikan akses jarak jauh ke &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; guna mengakses aplikasi yang diinstal di tablet ini saat terhubung."</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Izinkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; memberikan akses jarak jauh ke &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; guna mengakses aplikasi yang diinstal di perangkat ini saat terhubung."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"perangkat"</string>
diff --git a/packages/CompanionDeviceManager/res/values-is/strings.xml b/packages/CompanionDeviceManager/res/values-is/strings.xml
index 5376912..cdfc47a 100644
--- a/packages/CompanionDeviceManager/res/values-is/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-is/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"Veita &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; stjórn á: &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"úr"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Velja <xliff:g id="PROFILE_NAME">%1$s</xliff:g> sem &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; á að stjórna"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> fær aðgang að tilkynningum og heimildum síma, SMS, tengiliða og dagatals."</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> fær aðgang að tilkynningum og heimildum síma, SMS, tengiliða og dagatals."</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"Leyfa &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; að streyma forritum?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Leyfa &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; að veita &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; fjaraðgang að forritum sem eru sett upp í þessum síma þegar tenging er á."</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Leyfa &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; að veita &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; fjaraðgang að forritum sem eru sett upp í þessari spjaldtölvu þegar tenging er á."</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Leyfa &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; að veita &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; fjaraðgang að forritum sem eru sett upp í þessu tæki þegar tenging er á."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"tæki"</string>
diff --git a/packages/CompanionDeviceManager/res/values-it/strings.xml b/packages/CompanionDeviceManager/res/values-it/strings.xml
index af9e8ca..fc7100a 100644
--- a/packages/CompanionDeviceManager/res/values-it/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-it/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"Consenti all\'app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; di gestire &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"orologio"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Scegli un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> che sia gestito da &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"L\'app <xliff:g id="APP_NAME">%1$s</xliff:g> potrà interagire con le tue notifiche e accedere alle autorizzazioni Telefono, SMS, Contatti e Calendario."</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"L\'app <xliff:g id="APP_NAME">%1$s</xliff:g> potrà interagire con le tue notifiche e accedere alle autorizzazioni Telefono, SMS, Contatti e Calendario."</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"Vuoi consentire all\'app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; di riprodurre applicazioni in streaming?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Consenti all\'app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; di fornire l\'accesso remoto a &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; per accedere alle applicazioni installate su questo telefono quando è connesso."</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Consenti all\'app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; di fornire l\'accesso remoto a &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; per accedere alle applicazioni installate su questo tablet quando è connesso."</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Consenti all\'app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; di fornire l\'accesso remoto a &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; per accedere alle applicazioni installate su questo dispositivo quando è connesso."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
diff --git a/packages/CompanionDeviceManager/res/values-iw/strings.xml b/packages/CompanionDeviceManager/res/values-iw/strings.xml
index 68ca9d9..295df783 100644
--- a/packages/CompanionDeviceManager/res/values-iw/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-iw/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"‏אישור לאפליקציה &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; לנהל את &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"שעון"</string>
     <string name="chooser_title" msgid="2262294130493605839">"‏בחירת <xliff:g id="PROFILE_NAME">%1$s</xliff:g> לניהול באמצעות &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"‏האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> תוכל לבצע פעולות בהתראות ותקבל הרשאות גישה לטלפון, ל-SMS לאנשי הקשר וליומן."</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"‏האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> תוכל לבצע פעולות בהתראות ותקבל הרשאות גישה לטלפון, ל-SMS לאנשי הקשר וליומן."</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"‏לאפשר לאפליקציה &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; לשדר אפליקציות?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"‏האפליקציה &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; יכולה לספק ל-&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; גישה מרחוק כדי לגשת לאפליקציות שמותקנות בטלפון הזה כשיש חיבור."</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"‏האפליקציה &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; יכולה לספק ל-&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; גישה מרחוק כדי לגשת לאפליקציות שמותקנות בטאבלט הזה כשיש חיבור."</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"‏האפליקציה &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; יכולה לספק למכשיר &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; גישה מרחוק כדי לגשת לאפליקציות שמותקנות במכשיר הזה כשיש חיבור."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"מכשיר"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ja/strings.xml b/packages/CompanionDeviceManager/res/values-ja/strings.xml
index c10a1e1..a9438be 100644
--- a/packages/CompanionDeviceManager/res/values-ja/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ja/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; に &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; の管理を許可する"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"ウォッチ"</string>
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; の管理対象となる<xliff:g id="PROFILE_NAME">%1$s</xliff:g>の選択"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> は通知を使用でき、電話、SMS、連絡先、カレンダーの権限にもアクセスできるようになります。"</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> は通知を使用でき、電話、SMS、連絡先、カレンダーの権限にもアクセスできるようになります。"</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; にアプリのストリーミングを許可しますか?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"インターネット接続時に &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; がスマートフォン内にインストールされているアプリにリモートでアクセスすることを &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; に許可します。"</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"インターネット接続時に &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; がタブレット内にインストールされているアプリにリモートでアクセスすることを &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; に許可します。"</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"インターネット接続時に &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; がデバイス内にインストールされているアプリにリモートでアクセスすることを &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; に許可します。"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"デバイス"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ka/strings.xml b/packages/CompanionDeviceManager/res/values-ka/strings.xml
index 6372481..8354f4a 100644
--- a/packages/CompanionDeviceManager/res/values-ka/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ka/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"ნება დართეთ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>-ს&lt;/strong&gt;, რომ მართოს თქვენი &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"საათი"</string>
     <string name="chooser_title" msgid="2262294130493605839">"აირჩიეთ <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, რომელიც უნდა მართოს &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;-მა"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> შეძლებს თქვენს შეტყობინებებთან ინტერაქციას და თქვენი ტელეფონის, SMS-ების, კონტაქტებისა და კალენდრის ნებართვებზე წვდომას."</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> შეძლებს თქვენს შეტყობინებებთან ინტერაქციას და თქვენი ტელეფონის, SMS-ების, კონტაქტებისა და კალენდრის ნებართვებზე წვდომას."</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"გსურთ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-ს მისცეთ აპების სტრიმინგის საშუალება?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"მიეცით &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-ს საშუალება, &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;-ისთვის დაუშვას დისტანციური წვდომა ამ ტელეფონზე დაინსტალირებულ აპებზე მასთან დაკავშირებისას."</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"მიეცით &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-ს საშუალება, &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;-ისთვის დაუშვას დისტანციური წვდომა ამ ტაბლეტზე დაინსტალირებულ აპებზე მასთან დაკავშირებისას."</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"მიეცით &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-ს საშუალება, &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;-ისთვის დაუშვას დისტანციური წვდომა ამ მოწყობილობაზე დაინსტალირებულ აპებზე მასთან დაკავშირებისას."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"მოწყობილობა"</string>
diff --git a/packages/CompanionDeviceManager/res/values-kk/strings.xml b/packages/CompanionDeviceManager/res/values-kk/strings.xml
index 6ac9c04..722b570 100644
--- a/packages/CompanionDeviceManager/res/values-kk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-kk/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; қолданбасына &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; құрылғысын басқаруға рұқсат беру"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"сағат"</string>
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; арқылы басқарылатын <xliff:g id="PROFILE_NAME">%1$s</xliff:g> құрылғысын таңдаңыз"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасы хабарландыруларды, телефонды, SMS хабардарын, контактілерді және күнтізбе рұқсаттарын пайдалана алады."</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасы хабарландыруларды, телефонды, SMS хабардарын, контактілерді және күнтізбе рұқсаттарын пайдалана алады."</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; қолданбасына қолданбаларды трансляциялауға рұқсат етілсін бе?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; желіге қосылған кезде, &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; қолданбасына осы телефонға орнатылған қолданбаларды қашықтан пайдалануына рұқсат етіңіз."</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; желіге қосылған кезде, &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; қолданбасына осы планшетке орнатылған қолданбаларды қашықтан пайдалануына рұқсат етіңіз."</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; желіге қосылған кезде, &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; қолданбасына осы құрылғыға орнатылған қолданбаларды қашықтан пайдалануына рұқсат етіңіз."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"құрылғы"</string>
diff --git a/packages/CompanionDeviceManager/res/values-km/strings.xml b/packages/CompanionDeviceManager/res/values-km/strings.xml
index db2634f..d47d6c4 100644
--- a/packages/CompanionDeviceManager/res/values-km/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-km/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"អនុញ្ញាតឱ្យ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; គ្រប់គ្រង &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; របស់អ្នក"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"នាឡិកា"</string>
     <string name="chooser_title" msgid="2262294130493605839">"ជ្រើសរើស <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ដើម្បីឱ្យស្ថិតក្រោម​ការគ្រប់គ្រងរបស់ &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> នឹងត្រូវបានអនុញ្ញាតឱ្យ​ធ្វើអន្តរកម្មជាមួយ​ការជូនដំណឹងរបស់អ្នក និងចូលប្រើការអនុញ្ញាត​ប្រតិទិន, ទូរសព្ទ, SMS និងទំនាក់ទំនងរបស់អ្នក។"</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> នឹងត្រូវបានអនុញ្ញាតឱ្យ​ធ្វើអន្តរកម្មជាមួយ​ការជូនដំណឹងរបស់អ្នក និងចូលប្រើការអនុញ្ញាត​ប្រតិទិន, ទូរសព្ទ, SMS និងទំនាក់ទំនងរបស់អ្នក។"</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"អនុញ្ញាតឱ្យ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ផ្សាយកម្មវិធីឬ?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"អនុញ្ញាតឱ្យ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ផ្ដល់ការចូលប្រើពីចម្ងាយដល់ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ដើម្បីចូលប្រើកម្មវិធី ដែលបានដំឡើងនៅលើទូរសព្ទនេះ នៅពេលភ្ជាប់អ៊ីនធឺណិត។"</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"អនុញ្ញាតឱ្យ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ផ្ដល់ការចូលប្រើពីចម្ងាយដល់ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ដើម្បីចូលប្រើកម្មវិធី ដែលបានដំឡើងនៅលើថេប្លេតនេះ នៅពេលភ្ជាប់អ៊ីនធឺណិត។"</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"អនុញ្ញាតឱ្យ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ផ្ដល់ការចូលប្រើពីចម្ងាយដល់ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ដើម្បីចូលប្រើកម្មវិធី ដែលបានដំឡើងនៅលើឧបករណ៍នេះ នៅពេលភ្ជាប់អ៊ីនធឺណិត។"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"ឧបករណ៍"</string>
diff --git a/packages/CompanionDeviceManager/res/values-kn/strings.xml b/packages/CompanionDeviceManager/res/values-kn/strings.xml
index e6413da..ba9f8ff 100644
--- a/packages/CompanionDeviceManager/res/values-kn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-kn/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"ನಿಮ್ಮ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ಅನ್ನು ನಿರ್ವಹಿಸಲು &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ಅನ್ನು ಅನುಮತಿಸಿ"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"ವೀಕ್ಷಿಸಿ"</string>
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; ಮೂಲಕ ನಿರ್ವಹಿಸಬೇಕಾದ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ಅನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"ನಿಮ್ಮ ಅಧಿಸೂಚನೆಗಳೊಂದಿಗೆ ಸಂವಹನ ನಡೆಸಲು ಮತ್ತು ನಿಮ್ಮ ಫೋನ್, SMS, ಸಂಪರ್ಕಗಳು ಮತ್ತು Calendar ಅನುಮತಿಗಳನ್ನು ಪ್ರವೇಶಿಸಲು <xliff:g id="APP_NAME">%1$s</xliff:g> ಗೆ ಅನುಮತಿಸಲಾಗುತ್ತದೆ."</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"ನಿಮ್ಮ ಅಧಿಸೂಚನೆಗಳೊಂದಿಗೆ ಸಂವಹನ ನಡೆಸಲು ಮತ್ತು ನಿಮ್ಮ ಫೋನ್, SMS, ಸಂಪರ್ಕಗಳು ಮತ್ತು Calendar ಅನುಮತಿಗಳನ್ನು ಪ್ರವೇಶಿಸಲು <xliff:g id="APP_NAME">%1$s</xliff:g> ಗೆ ಅನುಮತಿಸಲಾಗುತ್ತದೆ."</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"ಆ್ಯಪ್‌ಗಳನ್ನು ಸ್ಟ್ರೀಮ್ ಮಾಡಲು <xliff:g id="APP_NAME">%1$s</xliff:g> ಗೆ ಅನುಮತಿಸಿ?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"ಕನೆಕ್ಟ್ ಆದಾಗ ಈ ಫೋನ್‌ನಲ್ಲಿ ಇನ್‌ಸ್ಟಾಲ್ ಮಾಡಲಾದ ಆ್ಯಪ್‌ಗಳನ್ನು ಪ್ರವೇಶಿಸುವುದಕ್ಕಾಗಿ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ಗೆ ರಿಮೋಟ್ ಪ್ರವೇಶವನ್ನು ಒದಗಿಸಲು &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ಗೆ ಅನುಮತಿಸಿ."</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"ಕನೆಕ್ಟ್ ಆದಾಗ ಈ ಟ್ಯಾಬ್ಲೆಟ್‌ನಲ್ಲಿ ಇನ್‌ಸ್ಟಾಲ್ ಮಾಡಲಾದ ಆ್ಯಪ್‌ಗಳನ್ನು ಪ್ರವೇಶಿಸುವುದಕ್ಕಾಗಿ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ಗೆ ರಿಮೋಟ್ ಪ್ರವೇಶವನ್ನು ಒದಗಿಸಲು &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ಗೆ ಅನುಮತಿಸಿ."</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"ಕನೆಕ್ಟ್ ಆದಾಗ ಈ ಸಾಧನದಲ್ಲಿ ಇನ್‌ಸ್ಟಾಲ್ ಮಾಡಲಾದ ಆ್ಯಪ್‌ಗಳನ್ನು ಪ್ರವೇಶಿಸುವುದಕ್ಕಾಗಿ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ಗೆ ರಿಮೋಟ್ ಪ್ರವೇಶವನ್ನು ಒದಗಿಸಲು &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ಗೆ ಅನುಮತಿಸಿ."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"ಸಾಧನ"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ko/strings.xml b/packages/CompanionDeviceManager/res/values-ko/strings.xml
index 02459d5..8faab71 100644
--- a/packages/CompanionDeviceManager/res/values-ko/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ko/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;에서 &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; 기기를 관리하도록 허용"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"시계"</string>
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;에서 관리할 <xliff:g id="PROFILE_NAME">%1$s</xliff:g>을(를) 선택"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g>에서 알림과 상호작용하고 전화, SMS, 연락처, 캘린더 권한에 액세스할 수 있게 됩니다."</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g>에서 알림과 상호작용하고 전화, SMS, 연락처, 캘린더 권한에 액세스할 수 있게 됩니다."</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;에서 애플리케이션을 스트리밍하도록 허용하시겠습니까?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"연결 시 &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;에서 &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;에 이 휴대전화에 설치된 애플리케이션에 원격으로 액세스할 수 있는 권한을 제공하도록 허용합니다."</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"연결 시 &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;에서 &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;에 이 태블릿에 설치된 애플리케이션에 원격으로 액세스할 수 있는 권한을 제공하도록 허용합니다."</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"연결 시 &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;에서 &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;에 이 기기에 설치된 애플리케이션에 원격으로 액세스할 수 있는 권한을 제공하도록 허용합니다."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"기기"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ky/strings.xml b/packages/CompanionDeviceManager/res/values-ky/strings.xml
index ea4230a..eec1775 100644
--- a/packages/CompanionDeviceManager/res/values-ky/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ky/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; колдонмосуна &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; түзмөгүңүздү башкарууга уруксат бериңиз"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"саат"</string>
     <string name="chooser_title" msgid="2262294130493605839">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g> &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; тарабынан башкарылсын"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> билдирмелериңизди көрүп, телефонуңуздун, SMS билдирүүлөрүңүздүн, байланыштарыңыздын жана жылнаамаңыздын уруксаттарын пайдалана алат."</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> билдирмелериңизди көрүп, телефонуңуздун, SMS билдирүүлөрүңүздүн, байланыштарыңыздын жана жылнаамаңыздын уруксаттарын пайдалана алат."</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; колдонмосуна колдонмолорду алып ойнотууга уруксат бересизби?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; колдонмосуна Интернетке туташкан &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; телефонундагы колдонмолорго алыстан кирүү мүмкүнчүлүгүн бериңиз."</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; колдонмосуна Интернетке туташкан &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; планшетиндеги колдонмолорго алыстан кирүү мүмкүнчүлүгүн бериңиз."</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; колдонмосуна Интернетке туташкан &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; түзмөгүндөгү колдонмолорго алыстан кирүү мүмкүнчүлүгүн бериңиз."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"түзмөк"</string>
diff --git a/packages/CompanionDeviceManager/res/values-lo/strings.xml b/packages/CompanionDeviceManager/res/values-lo/strings.xml
index b6c6289..ed24422 100644
--- a/packages/CompanionDeviceManager/res/values-lo/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-lo/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"ອະນຸຍາດໃຫ້ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ຈັດການ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ຂອງທ່ານໄດ້"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"ໂມງ"</string>
     <string name="chooser_title" msgid="2262294130493605839">"ເລືອກ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ເພື່ອໃຫ້ຖືກຈັດການໂດຍ &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ຈະໄດ້ຮັບອະນຸຍາດໃຫ້ໂຕ້ຕອບກັບການແຈ້ງເຕືອນຂອງທ່ານ ແລະ ເຂົ້າເຖິງການອະນຸຍາດໂທລະສັບ, SMS, ລາຍຊື່ຜູ້ຕິດຕໍ່ ແລະ ປະຕິທິນຂອງທ່ານໄດ້."</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ຈະໄດ້ຮັບອະນຸຍາດໃຫ້ໂຕ້ຕອບກັບການແຈ້ງເຕືອນຂອງທ່ານ ແລະ ເຂົ້າເຖິງການອະນຸຍາດໂທລະສັບ, SMS, ລາຍຊື່ຜູ້ຕິດຕໍ່ ແລະ ປະຕິທິນຂອງທ່ານໄດ້."</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"ອະນຸຍາດໃຫ້ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ສະຕຣີມແອັບພລິເຄຊັນໄດ້ບໍ?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"ໃຫ້ສິດ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ເພື່ອເຂົ້າເຖິງ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ຈາກໄລຍະໄກເພື່ອເຂົ້າເຖິງແອັບພລິເຄຊັນທີ່ຕິດຕັ້ງຢູ່ໂທລະສັບນີ້ເມື່ອເຊື່ອມຕໍ່ແລ້ວ."</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"ໃຫ້ສິດ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ເພື່ອເຂົ້າເຖິງ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ຈາກໄລຍະໄກເພື່ອເຂົ້າເຖິງແອັບພລິເຄຊັນທີ່ຕິດຕັ້ງຢູ່ແທັບເລັດນີ້ເມື່ອເຊື່ອມຕໍ່ແລ້ວ."</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"ໃຫ້ສິດ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ເພື່ອເຂົ້າເຖິງ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ຈາກໄລຍະໄກເພື່ອເຂົ້າເຖິງແອັບພລິເຄຊັນທີ່ຕິດຕັ້ງຢູ່ອຸປະກອນນີ້ເມື່ອເຊື່ອມຕໍ່ແລ້ວ."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"ອຸປະກອນ"</string>
diff --git a/packages/CompanionDeviceManager/res/values-lt/strings.xml b/packages/CompanionDeviceManager/res/values-lt/strings.xml
index e5ff480..8472d79 100644
--- a/packages/CompanionDeviceManager/res/values-lt/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-lt/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"Leisti &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tvarkyti &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"laikrodį"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Jūsų <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, kurį valdys &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; (pasirinkite)"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ galės sąveikauti su pranešimų funkcija ir pasiekti telefoną, SMS, kontaktus ir kalendorių."</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ galės sąveikauti su pranešimų funkcija ir pasiekti telefoną, SMS, kontaktus ir kalendorių."</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"Leisti &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; perduoti srautu programas?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Leiskite &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; prisijungus suteikti &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; nuotolinę prieigą prie šiame telefone įdiegtų programų."</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Leiskite &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; prisijungus suteikti &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; nuotolinę prieigą prie šiame planšetiniame kompiuteryje įdiegtų programų."</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Leiskite &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; prisijungus suteikti &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; nuotolinę prieigą prie šiame įrenginyje įdiegtų programų."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"įrenginys"</string>
diff --git a/packages/CompanionDeviceManager/res/values-lv/strings.xml b/packages/CompanionDeviceManager/res/values-lv/strings.xml
index d521240..8b27a08 100644
--- a/packages/CompanionDeviceManager/res/values-lv/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-lv/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"Atļauja lietotnei &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; pārvaldīt ierīci &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"pulkstenis"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Profila (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>) izvēle, ko pārvaldīt lietotnē &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"Lietotnei <xliff:g id="APP_NAME">%1$s</xliff:g> tiks atļauts mijiedarboties ar jūsu paziņojumiem un piekļūt šādām atļaujām: Tālrunis, Īsziņas, Kontaktpersonas un Kalendārs."</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"Lietotnei <xliff:g id="APP_NAME">%1$s</xliff:g> tiks atļauts mijiedarboties ar jūsu paziņojumiem un piekļūt šādām atļaujām: Tālrunis, Īsziņas, Kontaktpersonas un Kalendārs."</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"Vai atļaujat lietotnei &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; straumēt lietojumprogrammas?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Atļaut lietotnei &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; nodrošināt attālu piekļuvi tālrunim &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;, lai piekļūtu šajā tālrunī instalētajām lietojumprogrammām, kamēr ir izveidots savienojums."</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Atļaut lietotnei &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; nodrošināt attālu piekļuvi planšetdatoram &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;, lai piekļūtu šajā planšetdatorā instalētajām lietojumprogrammām, kamēr ir izveidots savienojums."</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Atļaut lietotnei &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; nodrošināt attālu piekļuvi ierīcei &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;, lai piekļūtu šajā ierīcē instalētajām lietojumprogrammām, kamēr ir izveidots savienojums."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"ierīce"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ml/strings.xml b/packages/CompanionDeviceManager/res/values-ml/strings.xml
index 639909a..e35a733 100644
--- a/packages/CompanionDeviceManager/res/values-ml/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ml/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"നിങ്ങളുടെ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; മാനേജ് ചെയ്യാൻ, &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; എന്നതിനെ അനുവദിക്കുക"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"വാച്ച്"</string>
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; ഉപയോഗിച്ച് മാനേജ് ചെയ്യുന്നതിന് ഒരു <xliff:g id="PROFILE_NAME">%1$s</xliff:g> തിരഞ്ഞെടുക്കുക"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"നിങ്ങളുടെ അറിയിപ്പുകളുമായി സംവദിക്കാനും നിങ്ങളുടെ ഫോൺ, SMS, കോൺടാക്റ്റുകൾ, കലണ്ടർ അനുമതികൾ എന്നിവ ആക്‌സസ് ചെയ്യാനും <xliff:g id="APP_NAME">%1$s</xliff:g> എന്നതിനെ അനുവദിക്കും."</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"നിങ്ങളുടെ അറിയിപ്പുകളുമായി സംവദിക്കാനും നിങ്ങളുടെ ഫോൺ, SMS, കോൺടാക്റ്റുകൾ, കലണ്ടർ അനുമതികൾ എന്നിവ ആക്‌സസ് ചെയ്യാനും <xliff:g id="APP_NAME">%1$s</xliff:g> എന്നതിനെ അനുവദിക്കും."</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"ആപ്പുകൾ സ്‌ട്രീം ചെയ്യാൻ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; എന്നതിനെ അനുവദിക്കണോ?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"കണക്‌റ്റ് ചെയ്യുമ്പോൾ, ഈ ഫോണിൽ ഇൻസ്‌റ്റാൾ ചെയ്‌തിട്ടുള്ള ആപ്പുകൾ ആക്‌സസ് ചെയ്യാനുള്ള റിമോട്ട് ആക്‌സസ് &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; എന്നതിന് നൽകാൻ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; എന്നതിനെ അനുവദിക്കുക."</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"കണക്‌റ്റ് ചെയ്യുമ്പോൾ, ഈ ടാബ്‌ലെറ്റിൽ ഇൻസ്‌റ്റാൾ ചെയ്‌തിട്ടുള്ള ആപ്പുകൾ ആക്‌സസ് ചെയ്യാനുള്ള റിമോട്ട് ആക്‌സസ് &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; എന്നതിന് നൽകാൻ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; എന്നതിനെ അനുവദിക്കുക."</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"കണക്‌റ്റ് ചെയ്യുമ്പോൾ, ഈ ഉപകരണത്തിൽ ഇൻസ്‌റ്റാൾ ചെയ്‌തിട്ടുള്ള ആപ്പുകൾ ആക്‌സസ് ചെയ്യാനുള്ള റിമോട്ട് ആക്‌സസ് &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; എന്നതിന് നൽകാൻ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; എന്നതിനെ അനുവദിക്കുക."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"ഉപകരണം"</string>
diff --git a/packages/CompanionDeviceManager/res/values-mn/strings.xml b/packages/CompanionDeviceManager/res/values-mn/strings.xml
index adbe62d..1ea1c9b 100644
--- a/packages/CompanionDeviceManager/res/values-mn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-mn/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;-г удирдахын тулд &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-г зөвшөөрнө үү"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"цаг"</string>
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;-н удирдах<xliff:g id="PROFILE_NAME">%1$s</xliff:g>-г сонгоно уу"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g>-д таны мэдэгдлүүдтэй харилцаж, таны Утас, SMS, Харилцагчид болон Календарийн зөвшөөрөлд хандахыг зөвшөөрнө."</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g>-д таны мэдэгдлүүдтэй харилцаж, таны Утас, SMS, Харилцагчид болон Календарийн зөвшөөрөлд хандахыг зөвшөөрнө."</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-д аппуудыг дамжуулахыг зөвшөөрөх үү?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-д &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;-г холбогдсон үед энэ утсанд суулгасан аппуудад хандахын тулд алсын хандалт өгөхийг зөвшөөрнө үү."</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-д &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;-г холбогдсон үед энэ таблетад суулгасан аппуудад хандахын тулд алсын хандалт өгөхийг зөвшөөрнө үү."</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-д &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;-г холбогдсон үед энэ төхөөрөмжид суулгасан аппуудад хандахын тулд алсын хандалт өгөхийг зөвшөөрнө үү."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"төхөөрөмж"</string>
diff --git a/packages/CompanionDeviceManager/res/values-mr/strings.xml b/packages/CompanionDeviceManager/res/values-mr/strings.xml
index fce0583..1936ede 100644
--- a/packages/CompanionDeviceManager/res/values-mr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-mr/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"तुमचे &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; व्यवस्थापित करण्यासाठी &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ला अनुमती द्या"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"वॉच"</string>
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; द्वारे व्यवस्थापित करण्यासाठी <xliff:g id="PROFILE_NAME">%1$s</xliff:g> निवडा"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ला तुमच्या सूचनांशी संवाद साधण्याची आणि तुमचा फोन, एसएमएस, संपर्क आणि Calendar च्या परवानग्या अ‍ॅक्सेस करण्याची अनुमती मिळेल."</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ला तुमच्या सूचनांशी संवाद साधण्याची आणि तुमचा फोन, एसएमएस, संपर्क आणि Calendar च्या परवानग्या अ‍ॅक्सेस करण्याची अनुमती मिळेल."</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ला अ‍ॅप्लिकेशन स्ट्रीम करण्याची अनुमती द्यायची आहे का?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"कनेक्ट केलेले असताना या फोनवरील अ‍ॅप्लिकेशन अ‍ॅक्सेस करता यावीत यासाठी &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ला &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; चा रिमोट अ‍ॅक्सेस द्या."</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"कनेक्ट केलेले असताना या टॅबलेटवरील अ‍ॅप्लिकेशन अ‍ॅक्सेस करता यावीत यासाठी &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ला &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; चा रिमोट अ‍ॅक्सेस द्या."</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"कनेक्ट केलेले असताना या डिव्हाइसवरील अ‍ॅप्लिकेशन अ‍ॅक्सेस करता यावीत यासाठी &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ला &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; चा रिमोट अ‍ॅक्सेस द्या."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"डिव्हाइस"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ms/strings.xml b/packages/CompanionDeviceManager/res/values-ms/strings.xml
index 5c4ec78..fb69cb1 100644
--- a/packages/CompanionDeviceManager/res/values-ms/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ms/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"Benarkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; untuk mengurus &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; anda"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"jam tangan"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Pilih <xliff:g id="PROFILE_NAME">%1$s</xliff:g> untuk diurus oleh &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> akan dibenarkan berinteraksi dengan pemberitahuan anda dan mengakses kebenaran Telefon, SMS, Kenalan dan Kalendar anda."</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> akan dibenarkan berinteraksi dengan pemberitahuan anda dan mengakses kebenaran Telefon, SMS, Kenalan dan Kalendar anda."</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"Benarkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; menstrim aplikasi?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Membenarkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; memberi akses jauh kepada &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; untuk mengakses aplikasi yang dipasang pada telefon ini apabila disambungkan."</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Membenarkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; memberi akses jauh kepada &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; untuk mengakses aplikasi yang dipasang pada tablet ini apabila disambungkan."</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Membenarkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; memberi akses jauh kepada &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; untuk mengakses aplikasi yang dipasang pada peranti ini apabila disambungkan."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"peranti"</string>
diff --git a/packages/CompanionDeviceManager/res/values-my/strings.xml b/packages/CompanionDeviceManager/res/values-my/strings.xml
index f3e572e..31596a4 100644
--- a/packages/CompanionDeviceManager/res/values-my/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-my/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"သင်၏ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ကို စီမံခန့်ခွဲရန် &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ကို ခွင့်ပြုပါ"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"နာရီ"</string>
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; က စီမံခန့်ခွဲရန် <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ကို ရွေးချယ်ပါ"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"သင်၏ ‘ဖုန်း’၊ ‘SMS စာတိုစနစ်’၊ ‘အဆက်အသွယ်များ’ နှင့် ‘ပြက္ခဒိန်’ ခွင့်ပြုချက်များကို သုံးရန်နှင့် အကြောင်းကြားချက်များကို ပြန်လှန်တုံ့ပြန်ရန် <xliff:g id="APP_NAME">%1$s</xliff:g> အား ခွင့်ပြုပါမည်။"</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"သင်၏ ‘ဖုန်း’၊ ‘SMS စာတိုစနစ်’၊ ‘အဆက်အသွယ်များ’ နှင့် ‘ပြက္ခဒိန်’ ခွင့်ပြုချက်များကို သုံးရန်နှင့် အကြောင်းကြားချက်များကို ပြန်လှန်တုံ့ပြန်ရန် <xliff:g id="APP_NAME">%1$s</xliff:g> အား ခွင့်ပြုပါမည်။"</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"အပလီကေးရှင်းများကို တိုက်ရိုက်လွှင့်ရန် &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ကိုခွင့်ပြုမလား။"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"ချိတ်ဆက်ထားသည့်အခါ ဤဖုန်းတွင် ထည့်သွင်းထားသော အပလီကေးရှင်းများကို သုံးခွင့်ရရန်အတွက် &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ကိုအဝေးမှ သုံးခွင့်ပေးနိုင်ရန် &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; အားခွင့်ပြုပါ။"</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"ချိတ်ဆက်ထားသည့်အခါ ဤတက်ဘလက်တွင် ထည့်သွင်းထားသော အပလီကေးရှင်းများကို သုံးခွင့်ရရန်အတွက် &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ကိုအဝေးမှ သုံးခွင့်ပေးနိုင်ရန် &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; အားခွင့်ပြုပါ။"</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"ချိတ်ဆက်ထားသည့်အခါ ဤစက်တွင် ထည့်သွင်းထားသော အပလီကေးရှင်းများကို သုံးခွင့်ရရန်အတွက် &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ကိုအဝေးမှ သုံးခွင့်ပေးနိုင်ရန် &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; အားခွင့်ပြုပါ။"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"စက်"</string>
diff --git a/packages/CompanionDeviceManager/res/values-nb/strings.xml b/packages/CompanionDeviceManager/res/values-nb/strings.xml
index d3eb7e5..52afcf0 100644
--- a/packages/CompanionDeviceManager/res/values-nb/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-nb/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"Tillat at &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; administrerer &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"klokke"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Velg <xliff:g id="PROFILE_NAME">%1$s</xliff:g> som skal administreres av &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> får tillatelse til å samhandle med varslene dine og får tilgang til Telefon, SMS, kontakter og Kalender."</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> får tillatelse til å samhandle med varslene dine og får tilgang til Telefon, SMS, kontakter og Kalender."</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"Vil du gi &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tillatelse til å strømme apper?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Tillat at &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; gir &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ekstern tilgang til apper som er installert på denne telefonen, når den er koblet til internett."</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Tillat at &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; gir &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ekstern tilgang til apper som er installert på dette nettbrettet, når det er koblet til internett."</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Tillat at &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; gir &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ekstern tilgang til apper som er installert på denne enheten, når den er koblet til internett."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"enhet"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ne/strings.xml b/packages/CompanionDeviceManager/res/values-ne/strings.xml
index 9bcf69b..9b42c1e 100644
--- a/packages/CompanionDeviceManager/res/values-ne/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ne/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"आफ्नो &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; लाई &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; व्यवस्थापन गर्ने अनुमति दिनुहोस्"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"घडी"</string>
     <string name="chooser_title" msgid="2262294130493605839">"आफूले &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; प्रयोग गरी व्यवस्थापन गर्न चाहेको <xliff:g id="PROFILE_NAME">%1$s</xliff:g> चयन गर्नुहोस्"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> लाई तपाईंका सूचना हेर्ने र फोन, SMS, कन्ट्याक्ट तथा पात्रोसम्बन्धी अनुमतिहरू हेर्ने तथा प्रयोग गर्ने अनुमति दिइने छ।"</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> लाई तपाईंका सूचना हेर्ने र फोन, SMS, कन्ट्याक्ट तथा पात्रोसम्बन्धी अनुमतिहरू हेर्ने तथा प्रयोग गर्ने अनुमति दिइने छ।"</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; लाई एपहरू स्ट्रिम गर्ने अनुमति दिने हो?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"यो डिभाइस इन्टरनेटमा कनेक्ट भएका बेला, &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;लाई &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; लाई यो फोनमा इन्स्टल गरिएका एप टाढैबाट प्रयोग गर्ने अनुमति दिन दिनुहोस्।"</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"यो डिभाइस इन्टरनेटमा कनेक्ट भएका बेला, &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;लाई &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; लाई यो ट्याब्लेटमा इन्स्टल गरिएका एप टाढैबाट प्रयोग गर्ने अनुमति दिन दिनुहोस्।"</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"यो डिभाइस इन्टरनेटमा कनेक्ट भएका बेला, &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; लाई &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; लाई यो डिभाइसमा इन्स्टल गरिएका एप टाढैबाट प्रयोग गर्ने अनुमति दिन दिनुहोस्।"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"यन्त्र"</string>
diff --git a/packages/CompanionDeviceManager/res/values-nl/strings.xml b/packages/CompanionDeviceManager/res/values-nl/strings.xml
index 9ee09db..354cb93 100644
--- a/packages/CompanionDeviceManager/res/values-nl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-nl/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; toestaan je &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; te beheren"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"horloge"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Een <xliff:g id="PROFILE_NAME">%1$s</xliff:g> kiezen om te beheren met &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> kan interactie hebben met je meldingen en toegang krijgen tot je rechten voor telefoon, sms, contacten en agenda."</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> kan interactie hebben met je meldingen en toegang krijgen tot je rechten voor telefoon, sms, contacten en agenda."</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"Toestaan dat &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; apps streamt?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Toestaan dat &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; als er verbinding is &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; externe toegang geeft tot apps die zijn geïnstalleerd op deze telefoon."</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Toestaan dat &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; als er verbinding is &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; externe toegang geeft tot apps die zijn geïnstalleerd op deze tablet."</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Toestaan dat &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; als er verbinding is &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; externe toegang geeft tot apps die zijn geïnstalleerd op dit apparaat."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"apparaat"</string>
diff --git a/packages/CompanionDeviceManager/res/values-or/strings.xml b/packages/CompanionDeviceManager/res/values-or/strings.xml
index e08ec28..b58ebd34 100644
--- a/packages/CompanionDeviceManager/res/values-or/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-or/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"ଆପଣଙ୍କ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;କୁ ପରିଚାଳନା କରିବା ପାଇଁ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;କୁ ଅନୁମତି ଦିଅନ୍ତୁ"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"ୱାଚ୍"</string>
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; ଦ୍ୱାରା ପରିଚାଳିତ ହେବା ପାଇଁ ଏକ <xliff:g id="PROFILE_NAME">%1$s</xliff:g>କୁ ବାଛନ୍ତୁ"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"ଆପଣଙ୍କ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ ସହ ଇଣ୍ଟରାକ୍ଟ କରିବା ଏବଂ ଆପଣଙ୍କ ଫୋନ, SMS, ଯୋଗାଯୋଗ ଓ କ୍ୟାଲେଣ୍ଡର ଅନୁମତିଗୁଡ଼ିକୁ ଆକ୍ସେସ କରିବା ପାଇଁ <xliff:g id="APP_NAME">%1$s</xliff:g>କୁ ଅନୁମତି ଦିଆଯିବ।"</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"ଆପଣଙ୍କ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ ସହ ଇଣ୍ଟରାକ୍ଟ କରିବା ଏବଂ ଆପଣଙ୍କ ଫୋନ, SMS, ଯୋଗାଯୋଗ ଓ କ୍ୟାଲେଣ୍ଡର ଅନୁମତିଗୁଡ଼ିକୁ ଆକ୍ସେସ କରିବା ପାଇଁ <xliff:g id="APP_NAME">%1$s</xliff:g>କୁ ଅନୁମତି ଦିଆଯିବ।"</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;କୁ ଆପ୍ଲିକେସନଗୁଡ଼ିକ ଷ୍ଟ୍ରିମ କରିବା ପାଇଁ ଅନୁମତି ଦେବେ କି?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;କୁ, ଏହି ଫୋନଟି ସଂଯୁକ୍ତ ହୋଇଥିବା ବେଳେ ଏଥିରେ ଇନଷ୍ଟଲ କରାଯାଇଥିବା ଆପ୍ଲିକେସନଗୁଡ଼ିକୁ ଆକ୍ସେସ କରିବା ପାଇଁ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;କୁ ରିମୋଟ ଆକ୍ସେସ ପ୍ରଦାନ କରିବାକୁ ଦିଅନ୍ତୁ।"</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;କୁ, ଏହି ଟାବଲେଟଟି ସଂଯୁକ୍ତ ହୋଇଥିବା ବେଳେ ଏଥିରେ ଇନଷ୍ଟଲ କରାଯାଇଥିବା ଆପ୍ଲିକେସନଗୁଡ଼ିକୁ ଆକ୍ସେସ କରିବା ପାଇଁ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;କୁ ରିମୋଟ ଆକ୍ସେସ ପ୍ରଦାନ କରିବାକୁ ଦିଅନ୍ତୁ।"</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;କୁ, ଏହି ଡିଭାଇସଟି ସଂଯୁକ୍ତ ହୋଇଥିବା ବେଳେ ଏଥିରେ ଇନଷ୍ଟଲ କରାଯାଇଥିବା ଆପ୍ଲିକେସନଗୁଡ଼ିକୁ ଆକ୍ସେସ କରିବା ପାଇଁ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;କୁ ରିମୋଟ ଆକ୍ସେସ ପ୍ରଦାନ କରିବାକୁ ଦିଅନ୍ତୁ।"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"ଡିଭାଇସ୍"</string>
diff --git a/packages/CompanionDeviceManager/res/values-pa/strings.xml b/packages/CompanionDeviceManager/res/values-pa/strings.xml
index e317a464f..f2a5c29 100644
--- a/packages/CompanionDeviceManager/res/values-pa/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pa/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ਨੂੰ ਤੁਹਾਡੇ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ਦਾ ਪ੍ਰਬੰਧਨ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਦਿਓ"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"ਸਮਾਰਟ-ਵਾਚ"</string>
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; ਵੱਲੋਂ ਪ੍ਰਬੰਧਿਤ ਕੀਤੇ ਜਾਣ ਲਈ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ਚੁਣੋ"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਨੂੰ ਤੁਹਾਡੀਆਂ ਸੂਚਨਾਵਾਂ ਨਾਲ ਅੰਤਰਕਿਰਿਆ ਕਰਨ ਅਤੇ ਤੁਹਾਡੇ ਫ਼ੋਨ, SMS, ਸੰਪਰਕ ਅਤੇ ਕੈਲੰਡਰ ਦੀਆਂ ਇਜਾਜ਼ਤਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਹੋਵੇਗੀ।"</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਨੂੰ ਤੁਹਾਡੀਆਂ ਸੂਚਨਾਵਾਂ ਨਾਲ ਅੰਤਰਕਿਰਿਆ ਕਰਨ ਅਤੇ ਤੁਹਾਡੇ ਫ਼ੋਨ, SMS, ਸੰਪਰਕ ਅਤੇ ਕੈਲੰਡਰ ਦੀਆਂ ਇਜਾਜ਼ਤਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਹੋਵੇਗੀ।"</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"ਕੀ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&amp;gt ਨੂੰ ਐਪਲੀਕੇਸ਼ਨਾਂ ਸਟ੍ਰੀਮ ਕਰਨ ਦੀ ਆਗਿਆ ਦੇਣੀ ਹੈ?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"ਕਨੈਕਟ ਹੋਣ \'ਤੇ ਇਸ ਫ਼ੋਨ \'ਤੇ ਸਥਾਪਤ ਐਪਲੀਕੇਸ਼ਨਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਲਈ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ਨੂੰ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ਨੂੰ ਰਿਮੋਟ ਪਹੁੰਚ ਮੁਹੱਈਆ ਕਰਵਾਉਣ ਦਿਓ।"</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"ਕਨੈਕਟ ਹੋਣ \'ਤੇ ਇਸ ਟੈਬਲੈੱਟ \'ਤੇ ਸਥਾਪਤ ਐਪਲੀਕੇਸ਼ਨਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਲਈ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ਨੂੰ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ਨੂੰ ਰਿਮੋਟ ਪਹੁੰਚ ਮੁਹੱਈਆ ਕਰਵਾਉਣ ਦਿਓ।"</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"ਕਨੈਕਟ ਹੋਣ \'ਤੇ ਇਸ ਡੀਵਾਈਸ \'ਤੇ ਸਥਾਪਤ ਐਪਲੀਕੇਸ਼ਨਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਲਈ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ਨੂੰ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ਨੂੰ ਰਿਮੋਟ ਪਹੁੰਚ ਮੁਹੱਈਆ ਕਰਵਾਉਣ ਦਿਓ।"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"ਡੀਵਾਈਸ"</string>
diff --git a/packages/CompanionDeviceManager/res/values-pl/strings.xml b/packages/CompanionDeviceManager/res/values-pl/strings.xml
index 6cb7cc6..9356792 100644
--- a/packages/CompanionDeviceManager/res/values-pl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pl/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"Zezwól na zarządzanie urządzeniem &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; przez aplikację &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"zegarek"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Wybierz profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, którym ma zarządzać aplikacja &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> będzie mogła korzystać z powiadomień oraz uprawnień dotyczących Telefonu, SMS-ów, Kontaktów i Kalendarza."</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> będzie mogła korzystać z powiadomień oraz uprawnień dotyczących Telefonu, SMS-ów, Kontaktów i Kalendarza."</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"Zezwolić aplikacji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; na strumieniowanie danych z aplikacji?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Zezwól na zapewnianie przez aplikację &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; zdalnego dostępu do aplikacji zainstalowanych na telefonie &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; po połączeniu jej z tym telefonem."</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Zezwól na zapewnianie przez aplikację &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; zdalnego dostępu do aplikacji zainstalowanych na tablecie &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; po połączeniu jej z tym tabletem."</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Zezwól na zapewnianie przez aplikację &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; zdalnego dostępu do aplikacji zainstalowanych na urządzeniu &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; po połączeniu jej z urządzeniem."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"urządzenie"</string>
diff --git a/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml b/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml
index 4306286..7d79608 100644
--- a/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"Permitir que o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; gerencie seu &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"relógio"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Escolha um <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para ser gerenciado pelo app &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> poderá interagir com suas notificações e acessar as permissões do Telefone, de SMS, de Contatos e da Agenda."</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> poderá interagir com suas notificações e acessar as permissões do Telefone, de SMS, de Contatos e da Agenda."</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"Permitir que o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; faça streaming de aplicativos?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Permita que o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; conceda ao &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; acesso remoto aos aplicativos instalados no smartphone quando ele estiver conectado."</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Permita que o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; conceda ao &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; acesso remoto aos aplicativos instalados no tablet quando ele estiver conectado."</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Permita que o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; conceda ao &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; acesso remoto aos aplicativos instalados no dispositivo quando ele estiver conectado."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
diff --git a/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml b/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml
index 8f05d49..bc30ed8 100644
--- a/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"Permita que a app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; faça a gestão do seu &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"relógio"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Escolha um <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para ser gerido pela app &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"A app <xliff:g id="APP_NAME">%1$s</xliff:g> poderá interagir com as suas notificações e aceder às autorizações do Telefone, SMS, Contactos e Calendário."</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"A app <xliff:g id="APP_NAME">%1$s</xliff:g> poderá interagir com as suas notificações e aceder às autorizações do Telefone, SMS, Contactos e Calendário."</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"Permitir que a app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; faça stream de aplicações?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Permita que a app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; forneça acesso remoto ao &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; para aceder a aplicações instaladas neste telemóvel quando estiver ligado."</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Permita que a app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; forneça acesso remoto ao &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; para aceder a aplicações instaladas neste tablet quando estiver ligado."</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Permita que a app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; forneça acesso remoto ao &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; para aceder a aplicações instaladas neste dispositivo quando estiver ligado."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
diff --git a/packages/CompanionDeviceManager/res/values-pt/strings.xml b/packages/CompanionDeviceManager/res/values-pt/strings.xml
index 4306286..7d79608 100644
--- a/packages/CompanionDeviceManager/res/values-pt/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pt/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"Permitir que o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; gerencie seu &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"relógio"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Escolha um <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para ser gerenciado pelo app &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> poderá interagir com suas notificações e acessar as permissões do Telefone, de SMS, de Contatos e da Agenda."</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> poderá interagir com suas notificações e acessar as permissões do Telefone, de SMS, de Contatos e da Agenda."</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"Permitir que o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; faça streaming de aplicativos?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Permita que o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; conceda ao &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; acesso remoto aos aplicativos instalados no smartphone quando ele estiver conectado."</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Permita que o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; conceda ao &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; acesso remoto aos aplicativos instalados no tablet quando ele estiver conectado."</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Permita que o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; conceda ao &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; acesso remoto aos aplicativos instalados no dispositivo quando ele estiver conectado."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ro/strings.xml b/packages/CompanionDeviceManager/res/values-ro/strings.xml
index 43a4de7..dd38f1f 100644
--- a/packages/CompanionDeviceManager/res/values-ro/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ro/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"Permiteți ca &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; să vă gestioneze dispozitivul &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"ceas"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Alegeți un profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g> pe care să îl gestioneze &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> va putea să interacționeze cu notificările dvs. și să vă acceseze permisiunile pentru Telefon, SMS-uri, Agendă și Calendar."</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> va putea să interacționeze cu notificările dvs. și să vă acceseze permisiunile pentru Telefon, SMS-uri, Agendă și Calendar."</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"Lăsați &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; să redea în stream aplicații?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Lăsați &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; să ofere acces la distanță pentru &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ca să se poată accesa aplicațiile instalate pe acest telefon când se conectează utilizatorul."</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Lăsați &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; să ofere acces la distanță pentru &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ca să se poată accesa aplicațiile instalate pe această tabletă când se conectează utilizatorul."</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Lăsați &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; să ofere acces la distanță pentru &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ca să se poată accesa aplicațiile instalate pe acest dispozitiv când se conectează utilizatorul."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"dispozitiv"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ru/strings.xml b/packages/CompanionDeviceManager/res/values-ru/strings.xml
index 6d5c0de..8e2b4d8 100644
--- a/packages/CompanionDeviceManager/res/values-ru/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ru/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"Разрешите приложению &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; управлять этим устройством: &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"часы"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Выберите устройство (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>), которым будет управлять приложение &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"Приложению \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" будет предоставлен доступ к уведомлениям, а также следующие разрешения: телефон, SMS, контакты и календарь."</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"Приложению \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" будет предоставлен доступ к уведомлениям, а также следующие разрешения: телефон, SMS, контакты и календарь."</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"Разрешить приложению &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; транслировать приложения?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Разрешить приложению &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; при наличии подключения предоставить устройству &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; удаленный доступ к приложениям, установленным на этом телефоне."</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Разрешить приложению &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; при наличии подключения предоставить устройству &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; удаленный доступ к приложениям, установленным на этом планшете."</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Разрешить приложению &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; при наличии подключения предоставить устройству &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; удаленный доступ к приложениям, установленным на этом устройстве."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"устройство"</string>
diff --git a/packages/CompanionDeviceManager/res/values-si/strings.xml b/packages/CompanionDeviceManager/res/values-si/strings.xml
index b4e28d8..489ecf9 100644
--- a/packages/CompanionDeviceManager/res/values-si/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-si/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; හට ඔබගේ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; කළමනාකරණය කිරීමට ඉඩ දෙන්න"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"ඔරලෝසුව"</string>
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; මගින් කළමනාකරණය කරනු ලැබීමට <xliff:g id="PROFILE_NAME">%1$s</xliff:g>ක් තෝරන්න"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ඔබගේ දැනුම්දීම් සමඟ අන්තර්ක්‍රියා කිරීමට සහ ඔබගේ දුරකථනය, කෙටි පණිවුඩ, සම්බන්ධතා සහ දින දර්ශන අවසර වෙත ප්‍රවේශ වීමට ඉඩ දෙනු ඇත."</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ඔබගේ දැනුම්දීම් සමඟ අන්තර්ක්‍රියා කිරීමට සහ ඔබගේ දුරකථනය, කෙටි පණිවුඩ, සම්බන්ධතා සහ දින දර්ශන අවසර වෙත ප්‍රවේශ වීමට ඉඩ දෙනු ඇත."</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; හට යෙදුම් ප්‍රවාහ කිරීමට ඉඩ දෙන්නද?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"සම්බන්ධ වූ විට මෙම දුරකථනයේ ස්ථාපනය කර ඇති යෙදුම් වෙත ප්‍රවේශ වීමට &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; හට &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; හට දුරස්ථ ප්‍රවේශය ලබා දීමට ඉඩ දෙන්න."</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"සම්බන්ධ වූ විට මෙම ටැබ්ලටයේ ස්ථාපනය කර ඇති යෙදුම් වෙත ප්‍රවේශ වීමට &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; හට &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; හට දුරස්ථ ප්‍රවේශය ලබා දීමට ඉඩ දෙන්න."</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"සම්බන්ධ වූ විට මෙම උපාංගයේ ස්ථාපනය කර ඇති යෙදුම් වෙත ප්‍රවේශ වීමට &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; හට &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; හට දුරස්ථ ප්‍රවේශය ලබා දීමට ඉඩ දෙන්න."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"උපාංගය"</string>
diff --git a/packages/CompanionDeviceManager/res/values-sk/strings.xml b/packages/CompanionDeviceManager/res/values-sk/strings.xml
index 4f86f08..cbee372 100644
--- a/packages/CompanionDeviceManager/res/values-sk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sk/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"Povoliť aplikácii &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; spravovať zariadenie &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"hodinky"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Vyberte profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, ktorý bude spravovať aplikácia &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> bude môcť interagovať s vašimi upozorneniami a získavať prístup k povoleniam telefónu, SMS, kontaktov a kalendára."</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> bude môcť interagovať s vašimi upozorneniami a získavať prístup k povoleniam telefónu, SMS, kontaktov a kalendára."</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"Chcete aplikácii &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; povoliť streamovanie aplikácií?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Povoľte aplikácii &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; vzdialený prístup k telefónu &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;, aby mala po pripojení prístup k aplikáciám, ktoré sú v ňom nainštalované."</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Povoľte aplikácii &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; vzdialený prístup k tabletu &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;, aby mala po pripojení prístup k aplikáciám, ktoré sú v ňom nainštalované."</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Povoľte aplikácii &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; vzdialený prístup k zariadeniu &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;, aby mala po pripojení prístup k aplikáciám, ktoré sú v ňom nainštalované."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"zariadenie"</string>
diff --git a/packages/CompanionDeviceManager/res/values-sl/strings.xml b/packages/CompanionDeviceManager/res/values-sl/strings.xml
index a54af21..53eb85d 100644
--- a/packages/CompanionDeviceManager/res/values-sl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sl/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"Aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; dovolite upravljanje naprave &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"ura"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Izbira naprave <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, ki jo bo upravljala aplikacija &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"Aplikaciji <xliff:g id="APP_NAME">%1$s</xliff:g> bosta omogočena interakcija z obvestili in dostop do dovoljenj za telefon, sporočila SMS, stike in koledar."</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"Aplikaciji <xliff:g id="APP_NAME">%1$s</xliff:g> bosta omogočena interakcija z obvestili in dostop do dovoljenj za telefon, sporočila SMS, stike in koledar."</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"Želite aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; dovoliti pretočno predvajanje aplikacij?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; dovoli oddaljen dostop do telefona &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; za dostop do aplikacij, nameščenih v tem telefonu, ko je povezan v internet."</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; dovoli oddaljen dostop do tabličnega računalnika &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; za dostop do aplikacij, nameščenih v tem tabličnem računalniku, ko je povezan v internet."</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; dovoli oddaljen dostop do naprave &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; za dostop do aplikacij, nameščenih v tej napravi, ko je povezana v internet."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"naprava"</string>
diff --git a/packages/CompanionDeviceManager/res/values-sq/strings.xml b/packages/CompanionDeviceManager/res/values-sq/strings.xml
index d3f97df..0704b9b 100644
--- a/packages/CompanionDeviceManager/res/values-sq/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sq/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"Lejo që &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; të menaxhojë pajisjen tënde &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"ora inteligjente"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Zgjidh një profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g> që do të menaxhohet nga &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> do të lejohet të ndërveprojë me njoftimet e tua dhe të ketë qasje te lejet e \"Telefonit\", \"SMS-ve\", \"Kontakteve\" dhe \"Kalendarit\"."</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> do të lejohet të ndërveprojë me njoftimet e tua dhe të ketë qasje te lejet e \"Telefonit\", \"SMS-ve\", \"Kontakteve\" dhe \"Kalendarit\"."</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"Të lejohet që &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; të transmetojë aplikacionet?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Lejo që &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; të ofrojë &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; qasje në distancë për të pasur qasje në aplikacionet e instaluara në këtë telefon kur lidhet."</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Lejo që &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; të ofrojë &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; qasje në distancë për të pasur qasje në aplikacionet e instaluara në këtë tablet kur lidhet."</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Lejo që &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; t\'i ofrojë &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; qasje në distancë për të pasur qasje në aplikacionet e instaluara në këtë pajisje kur lidhet."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"pajisja"</string>
diff --git a/packages/CompanionDeviceManager/res/values-sr/strings.xml b/packages/CompanionDeviceManager/res/values-sr/strings.xml
index db8f291..eb768a2 100644
--- a/packages/CompanionDeviceManager/res/values-sr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sr/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"Дозволите апликацији &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да управља уређајем &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"сат"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Одаберите профил <xliff:g id="PROFILE_NAME">%1$s</xliff:g> којим ће управљати апликација &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ће добити дозволу за интеракцију са обавештењима и приступ дозволама за телефон, SMS поруке, контакте и календар."</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ће добити дозволу за интеракцију са обавештењима и приступ дозволама за телефон, SMS поруке, контакте и календар."</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"Желите да дозволите апликацији &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да стримује апликације?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Дозволите апликацији &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да даљински приступа апликацијама инсталираним на телефону &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; када је повезан."</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Дозволите апликацији &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да даљински приступа апликацијама инсталираним на таблету &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; када је повезан."</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Дозволите апликацији &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да даљински приступа апликацијама инсталираним на уређају &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; када је повезан."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"уређај"</string>
diff --git a/packages/CompanionDeviceManager/res/values-sv/strings.xml b/packages/CompanionDeviceManager/res/values-sv/strings.xml
index 733b2f7..24db58d 100644
--- a/packages/CompanionDeviceManager/res/values-sv/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sv/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"Tillåt att &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; hanterar din &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"klocka"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Välj en <xliff:g id="PROFILE_NAME">%1$s</xliff:g> för hantering av &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> får behörighet att interagera med dina aviseringar och komma åt behörigheterna för Telefon, Sms, Kontakter och Kalender."</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> får behörighet att interagera med dina aviseringar och komma åt behörigheterna för Telefon, Sms, Kontakter och Kalender."</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"Vill du tillåta att &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; streamar appar?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Låt &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ge &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; fjärråtkomst till åt appar som är installerade på den här telefonen när den är ansluten."</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Låt &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ge &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; fjärråtkomst till appar som är installerade på den här surfplattan när den är ansluten."</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Låt &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ge &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; fjärråtkomst till appar som är installerade på den här enheten när den är ansluten."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"enhet"</string>
diff --git a/packages/CompanionDeviceManager/res/values-sw/strings.xml b/packages/CompanionDeviceManager/res/values-sw/strings.xml
index 02db256..d06f1c6 100644
--- a/packages/CompanionDeviceManager/res/values-sw/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sw/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"Ruhusu &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; idhibiti &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; yako"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"saa"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Chagua <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ili idhibitiwe na &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> itaruhusiwa kufikia arifa zako na kufikia ruhusa za Simu, SMS, Anwani na Kalenda yako."</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> itaruhusiwa kufikia arifa zako na kufikia ruhusa za Simu, SMS, Anwani na Kalenda yako."</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"Ungependa kuruhusu &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; itiririshe programu?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Ruhusu &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; iipe &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ufikiaji wa mbali wa programu zilizosakinishwa kwenye simu hii wakati imeunganishwa."</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Ruhusu &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; iipe &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ufikiaji wa mbali wa programu zilizosakinishwa kwenye kompyuta hii kibao wakati imeunganishwa."</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Ruhusu &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; iipe &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ufikiaji wa mbali wa programu zilizosakinishwa kwenye kifaa hiki wakati kimeunganishwa."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"kifaa"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ta/strings.xml b/packages/CompanionDeviceManager/res/values-ta/strings.xml
index 3e998c8..d58d2ae 100644
--- a/packages/CompanionDeviceManager/res/values-ta/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ta/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"உங்கள் &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ஐ நிர்வகிக்க &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ஆப்ஸை அனுமதியுங்கள்"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"வாட்ச்"</string>
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; ஆப்ஸ் நிர்வகிக்கக்கூடிய <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ஐத் தேர்ந்தெடுங்கள்"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"உங்கள் அறிவிப்புகளைப் பார்க்கவும் மொபைல், மெசேஜ், தொடர்புகள், கேலெண்டர் ஆகியவற்றை அணுகவும் <xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸுக்கு அனுமதி வழங்கப்படும்."</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"உங்கள் அறிவிப்புகளைப் பார்க்கவும் மொபைல், மெசேஜ், தொடர்புகள், கேலெண்டர் ஆகியவற்றை அணுகவும் <xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸுக்கு அனுமதி வழங்கப்படும்."</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"ஆப்ஸை ஸ்ட்ரீம் செய்ய &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ஆப்ஸை அனுமதிக்கவா?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"இணைக்கப்பட்டிருக்கும்போது இந்த மொபைலில் நிறுவப்பட்டிருக்கும் ஆப்ஸை அணுகுவதற்கான தொலைநிலை அணுகலை &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; சாதனத்திற்கு வழங்க &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ஆப்ஸை அனுமதிக்கும்."</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"இணைக்கப்பட்டிருக்கும்போது இந்த டேப்லெட்டில் நிறுவப்பட்டிருக்கும் ஆப்ஸை அணுகுவதற்கான தொலைநிலை அணுகலை &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; சாதனத்திற்கு வழங்க &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ஆப்ஸை அனுமதிக்கும்."</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"இணைக்கப்பட்டிருக்கும்போது இந்தச் சாதனத்தில் நிறுவப்பட்டிருக்கும் ஆப்ஸை அணுகுவதற்கான தொலைநிலை அணுகலை &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; சாதனத்திற்கு வழங்க &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ஆப்ஸை அனுமதிக்கும்."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"சாதனம்"</string>
diff --git a/packages/CompanionDeviceManager/res/values-te/strings.xml b/packages/CompanionDeviceManager/res/values-te/strings.xml
index 8c53126..9e9fec5 100644
--- a/packages/CompanionDeviceManager/res/values-te/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-te/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"మీ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;ను మేనేజ్ చేయడానికి &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ను అనుమతించండి;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"వాచ్"</string>
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; ద్వారా మేనేజ్ చేయబడటానికి ఒక <xliff:g id="PROFILE_NAME">%1$s</xliff:g>ను ఎంచుకోండి"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"మీ నోటిఫికేషన్‌లతో ఇంటరాక్ట్ అవ్వడానికి ఇంకా మీ ఫోన్, SMS, కాంటాక్ట్‌లు, Calendar అనుమతులను యాక్సెస్ చేయడానికి <xliff:g id="APP_NAME">%1$s</xliff:g> అనుమతించబడుతుంది."</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"మీ నోటిఫికేషన్‌లతో ఇంటరాక్ట్ అవ్వడానికి ఇంకా మీ ఫోన్, SMS, కాంటాక్ట్‌లు, Calendar అనుమతులను యాక్సెస్ చేయడానికి <xliff:g id="APP_NAME">%1$s</xliff:g> అనుమతించబడుతుంది."</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"యాప్‌లను స్ట్రీమ్ చేయడానికి &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ను అనుమతించాలా?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"కనెక్ట్ అయినప్పుడు ఈ ఫోన్‌లో ఇన్‌స్టాల్ చేయబడిన యాప్‌లను యాక్సెస్ చేయడానికి &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; రిమోట్ యాక్సెస్‌ను అందించడానికి &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ను అనుమతించండి."</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"కనెక్ట్ అయినప్పుడు ఈ టాబ్లెట్‌లో ఇన్‌స్టాల్ చేయబడిన యాప్‌లను యాక్సెస్ చేయడానికి &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; రిమోట్ యాక్సెస్‌ను అందించడానికి &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ను అనుమతించండి."</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"కనెక్ట్ అయినప్పుడు ఈ పరికరంలో ఇన్‌స్టాల్ చేయబడిన యాప్‌లను యాక్సెస్ చేయడానికి &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; రిమోట్ యాక్సెస్‌ను అందించడానికి &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ను అనుమతించండి."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"పరికరం"</string>
diff --git a/packages/CompanionDeviceManager/res/values-th/strings.xml b/packages/CompanionDeviceManager/res/values-th/strings.xml
index 504731e..9d9c91d 100644
--- a/packages/CompanionDeviceManager/res/values-th/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-th/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"อนุญาตให้ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; จัดการ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ของคุณ"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"นาฬิกา"</string>
     <string name="chooser_title" msgid="2262294130493605839">"เลือก<xliff:g id="PROFILE_NAME">%1$s</xliff:g>ที่จะให้มีการจัดการโดย &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> จะได้รับอนุญาตให้โต้ตอบกับการแจ้งเตือนและได้รับสิทธิ์เข้าถึงโทรศัพท์, SMS, รายชื่อติดต่อ และปฏิทิน"</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> จะได้รับอนุญาตให้โต้ตอบกับการแจ้งเตือนและได้รับสิทธิ์เข้าถึงโทรศัพท์, SMS, รายชื่อติดต่อ และปฏิทิน"</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"อนุญาตให้ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; สตรีมแอปพลิเคชันใช่ไหม"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"อนุญาตให้ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; มอบสิทธิ์เข้าถึงแอปพลิเคชันที่ติดตั้งในโทรศัพท์เครื่องนี้จากระยะไกลให้แก่ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; เมื่อมีการเชื่อมต่อ"</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"อนุญาตให้ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; มอบสิทธิ์เข้าถึงแอปพลิเคชันที่ติดตั้งในแท็บเล็ตเครื่องนี้จากระยะไกลให้แก่ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; เมื่อมีการเชื่อมต่อ"</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"อนุญาตให้ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; มอบสิทธิ์เข้าถึงแอปพลิเคชันที่ติดตั้งในอุปกรณ์เครื่องนี้จากระยะไกลให้แก่ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; เมื่อมีการเชื่อมต่อ"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"อุปกรณ์"</string>
diff --git a/packages/CompanionDeviceManager/res/values-tl/strings.xml b/packages/CompanionDeviceManager/res/values-tl/strings.xml
index 30d5e57..436097c 100644
--- a/packages/CompanionDeviceManager/res/values-tl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-tl/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"Payagan ang &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; na pamahalaan ang iyong &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"relo"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Pumili ng <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para pamahalaan ng &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"Papayagan ang <xliff:g id="APP_NAME">%1$s</xliff:g> na makipag-ugnayan sa mga notification mo at ma-access ang iyong mga pahintulot sa Telepono, SMS, Mga Contact, at Kalendaryo."</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"Papayagan ang <xliff:g id="APP_NAME">%1$s</xliff:g> na makipag-ugnayan sa mga notification mo at ma-access ang iyong mga pahintulot sa Telepono, SMS, Mga Contact, at Kalendaryo."</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"Payagan ang &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; na mag-stream ng mga application?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Payagan ang &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; na bigyan ang &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ng malayuang access para ma-access ang mga application na naka-install sa teleponong ito kapag nakakonekta."</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Payagan ang &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; na bigyan ang &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ng malayuang access para ma-access ang mga application na naka-install sa tablet na ito kapag nakakonekta."</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Payagan ang &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; na bigyan ang &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ng malayuang access para ma-access ang mga application na naka-install sa device na ito kapag nakakonekta."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"device"</string>
diff --git a/packages/CompanionDeviceManager/res/values-tr/strings.xml b/packages/CompanionDeviceManager/res/values-tr/strings.xml
index 1b1d71d..3a256a7 100644
--- a/packages/CompanionDeviceManager/res/values-tr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-tr/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; uygulaması &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; cihazınızı yönetebilsin mi?"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"saat"</string>
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; tarafından yönetilecek bir <xliff:g id="PROFILE_NAME">%1$s</xliff:g> seçin"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> adlı uygulamanın bildirimlerinizle etkileşimde bulunup Telefon, SMS, Kişiler ve Takvim izinlerinize erişmesine izin verilir."</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> adlı uygulamanın bildirimlerinizle etkileşimde bulunup Telefon, SMS, Kişiler ve Takvim izinlerinize erişmesine izin verilir."</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; uygulamasının, uygulamalarda akış gerçekleştirmesine izin verilsin mi?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; uygulamasının, internete bağlanan bu telefondaki yüklü uygulamalara erişebilmesi için &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; adlı cihaza uzaktan erişim izni verin."</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; uygulamasının, internete bağlanan bu tabletteki yüklü uygulamalara erişebilmesi için &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; adlı cihaza uzaktan erişim izni verin."</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; uygulamasının, internete bağlanan bu cihazdaki yüklü uygulamalara erişebilmesi için &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; adlı cihaza uzaktan erişim izni verin."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"cihaz"</string>
diff --git a/packages/CompanionDeviceManager/res/values-uk/strings.xml b/packages/CompanionDeviceManager/res/values-uk/strings.xml
index 149841a..9f40a0c 100644
--- a/packages/CompanionDeviceManager/res/values-uk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-uk/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"Дозволити додатку &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; керувати вашим пристроєм &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"годинник"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Виберіть <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, яким керуватиме додаток &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"Додаток <xliff:g id="APP_NAME">%1$s</xliff:g> зможе взаємодіяти з вашими сповіщеннями та отримає дозволи \"Телефон\", \"SMS\", \"Контакти\" й \"Календар\"."</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"Додаток <xliff:g id="APP_NAME">%1$s</xliff:g> зможе взаємодіяти з вашими сповіщеннями та отримає дозволи \"Телефон\", \"SMS\", \"Контакти\" й \"Календар\"."</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"Дозволити додатку &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; транслювати інші додатки?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Дозвольте додатку &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; за наявності з’єднання надавати пристрою &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; віддалений доступ до додатків, установлених на цьому телефоні."</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Дозвольте додатку &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; за наявності з’єднання надавати пристрою &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; віддалений доступ до додатків, установлених на цьому планшеті."</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Дозвольте додатку &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; за наявності з’єднання надавати пристрою &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; віддалений доступ до додатків, установлених на цьому пристрої."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"пристрій"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ur/strings.xml b/packages/CompanionDeviceManager/res/values-ur/strings.xml
index b467550..3c1fe5d 100644
--- a/packages/CompanionDeviceManager/res/values-ur/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ur/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"‏اپنے &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; کا نظم کرنے کے لیے ‎&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; کو اجازت دیں"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"دیکھیں"</string>
     <string name="chooser_title" msgid="2262294130493605839">"‏&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; کے ذریعے نظم کئے جانے کیلئے <xliff:g id="PROFILE_NAME">%1$s</xliff:g> کو منتخب کریں"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"‏<xliff:g id="APP_NAME">%1$s</xliff:g> کو آپ کی اطلاعات کے ساتھ تعامل کرنے اور آپ کے فون، SMS، رابطوں اور کیلنڈر کی اجازتوں تک رسائی کی اجازت ہوگی۔"</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"‏<xliff:g id="APP_NAME">%1$s</xliff:g> کو آپ کی اطلاعات کے ساتھ تعامل کرنے اور آپ کے فون، SMS، رابطوں اور کیلنڈر کی اجازتوں تک رسائی کی اجازت ہوگی۔"</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"‏&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; کو ایپلیکیشنز کی سلسلہ بندی کرنے کی اجازت دیں؟"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"‏منسلک ہونے پر، اس فون پر انسٹال کردہ ایپلیکیشنز تک رسائی حاصل کرنے کے لیے &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; کو &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>‏&lt;/strong&gt; کے لیے ریموٹ تک رسائی فراہم کرنے کی اجازت دیں۔"</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"‏منسلک ہونے پر، اس ٹیبلیٹ پر انسٹال کردہ ایپلیکیشنز تک رسائی حاصل کرنے کے لیے &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; کو &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>‏&lt;/strong&gt; کے لیے ریموٹ تک رسائی فراہم کرنے کی اجازت دیں۔"</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"‏منسلک ہونے پر، اس آلے پر انسٹال کردہ ایپلیکیشنز تک رسائی حاصل کرنے کے لیے &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; کو &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>‏&lt;/strong&gt; کے لیے ریموٹ تک رسائی فراہم کرنے کی اجازت دیں۔"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"آلہ"</string>
diff --git a/packages/CompanionDeviceManager/res/values-uz/strings.xml b/packages/CompanionDeviceManager/res/values-uz/strings.xml
index 8505ca9..ff5e4b9 100644
--- a/packages/CompanionDeviceManager/res/values-uz/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-uz/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; qurilmasini boshqarish uchun &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ilovasiga ruxsat bering"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"soat"</string>
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; boshqaradigan <xliff:g id="PROFILE_NAME">%1$s</xliff:g> qurilmasini tanlang"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ilovasiga bildirishnomalar bilan ishlash va telefon, SMS, kontaktlar va taqvimga kirishga ruxsat beriladi"</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ilovasiga bildirishnomalar bilan ishlash va telefon, SMS, kontaktlar va taqvimga kirishga ruxsat beriladi"</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ilovasiga ilovalarni strim qilishi uchun ruxsat berilsinmi?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ilovasiga &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ulanganda ushbu telefonda oʻrnatilgan ilovalarga masofadan kirish ruxsatini bering."</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ilovasiga &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ulanganda ushbu planshetda oʻrnatilgan ilovalarga masofadan kirish ruxsatini bering."</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ilovasiga &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ulanganda ushbu qurilmada oʻrnatilgan ilovalarga masofadan kirish ruxsatini bering."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"qurilma"</string>
diff --git a/packages/CompanionDeviceManager/res/values-vi/strings.xml b/packages/CompanionDeviceManager/res/values-vi/strings.xml
index 5dec271..f52dde1 100644
--- a/packages/CompanionDeviceManager/res/values-vi/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-vi/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"Cho phép &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; quản lý &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; của bạn"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"đồng hồ"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Chọn một <xliff:g id="PROFILE_NAME">%1$s</xliff:g> sẽ do &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; quản lý"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> sẽ được phép tương tác với thông báo cũng như truy cập vào Điện thoại, SMS, Danh bạ và Lịch."</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> sẽ được phép tương tác với thông báo cũng như truy cập vào Điện thoại, SMS, Danh bạ và Lịch."</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"Cho phép &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; truyền trực tuyến ứng dụng?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Cho phép &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; truy cập từ xa vào các ứng dụng đã cài đặt trên &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; khi điện thoại này có kết nối."</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Cho phép &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; truy cập từ xa vào các ứng dụng đã cài đặt trên &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; khi máy tính bảng này có kết nối."</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Cho phép &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; truy cập từ xa vào các ứng dụng đã cài đặt trên &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; khi thiết bị này có kết nối."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"thiết bị"</string>
diff --git a/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml
index f414067..f1facc1 100644
--- a/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"允许&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;管理您的&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"手表"</string>
     <string name="chooser_title" msgid="2262294130493605839">"选择要由&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;管理的<xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"“<xliff:g id="APP_NAME">%1$s</xliff:g>”将能与通知互动,并可访问电话、短信、通讯录和日历。"</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"“<xliff:g id="APP_NAME">%1$s</xliff:g>”将能与通知互动,并可访问电话、短信、通讯录和日历。"</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"是否允许 &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; 流式传输应用?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"在 &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; 连接到网络后,允许 &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; 远程访问该手机上安装的应用。"</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"在 &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; 连接到网络后,允许 &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; 远程访问该平板电脑上安装的应用。"</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"在 &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; 连接到网络后,允许 &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; 远程访问该设备上安装的应用。"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"设备"</string>
diff --git a/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml
index 37f4bd9..aed008f 100644
--- a/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"允許 &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; 管理您的&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"手錶"</string>
     <string name="chooser_title" msgid="2262294130493605839">"選擇由 &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; 管理的<xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」將可存取通知、電話、短訊、聯絡人和日曆資料。"</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」將可存取通知、電話、短訊、聯絡人和日曆資料。"</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;串流播放應用程式的內容嗎?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"讓「<xliff:g id="APP_NAME">%1$s</xliff:g>」在「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」連線時可透過遠端方式存取此手機上安裝的應用程式。"</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"讓「<xliff:g id="APP_NAME">%1$s</xliff:g>」在「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」連線時可透過遠端方式存取此平板電腦上安裝的應用程式。"</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"讓「<xliff:g id="APP_NAME">%1$s</xliff:g>」在「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」連線時可透過遠端方式存取此裝置上安裝的應用程式。"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"裝置"</string>
diff --git a/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml
index 76c8379..22a9d9c 100644
--- a/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;管理你的「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"手錶"</string>
     <string name="chooser_title" msgid="2262294130493605839">"選擇要讓「<xliff:g id="APP_NAME">%2$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;管理的<xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」將可存取通知、電話、簡訊、聯絡人和日曆資料。"</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」將可存取通知、電話、簡訊、聯絡人和日曆資料。"</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;串流播放應用程式的內容嗎?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;在「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;連上網際網路時可從遠端存取該手機上安裝的應用程式。"</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;在「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;連上網際網路時可從遠端存取該平板電腦上安裝的應用程式。"</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;在「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;連上網際網路時可從遠端存取該裝置上安裝的應用程式。"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"裝置"</string>
diff --git a/packages/CompanionDeviceManager/res/values-zu/strings.xml b/packages/CompanionDeviceManager/res/values-zu/strings.xml
index fdfda00..5c5756b 100644
--- a/packages/CompanionDeviceManager/res/values-zu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zu/strings.xml
@@ -20,18 +20,12 @@
     <string name="confirmation_title" msgid="8455544820286920304">"Vumela i-&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ukuthi iphathe i-&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; yakho"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"buka"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Khetha i-<xliff:g id="PROFILE_NAME">%1$s</xliff:g> ezophathwa yi-&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for summary_watch (7113724443198337683) -->
-    <skip />
-    <!-- no translation found for title_app_streaming (4459136600249308574) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (6105916810614498138) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (2996373715966272792) -->
-    <skip />
-    <!-- no translation found for summary_app_streaming (7614171699434639963) -->
-    <skip />
+    <string name="summary_watch" product="default" msgid="7113724443198337683">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> izovunyelwa ukuxhumana nezaziso zakho futhi ifinyelele izimvume Zefoni yakho, -SMS, Abathintwayo kanye Nekhalenda."</string>
+    <string name="summary_watch" product="tablet" msgid="7113724443198337683">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> izovunyelwa ukuxhumana nezaziso zakho futhi ifinyelele izimvume Zefoni yakho, -SMS, Abathintwayo kanye Nekhalenda."</string>
+    <string name="title_app_streaming" msgid="4459136600249308574">"Vumela &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ukusakaza ama-applications?"</string>
+    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Vumela &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ukunikezela &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ngokufinyelela kwerimothi kuma-applications afakiwe kule foni uma ixhunyiwe."</string>
+    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Vumela &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ukunikezela &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ngokufinyelela kwerimothi kuma-applications afakiwe kule thebhulethi uma ixhunyiwe."</string>
+    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Vumela &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ukunikezela &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ngokufinyelela kwerimothi kuma-applications afakiwe kule divayisi uma ixhunyiwe."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="profile_name_generic" msgid="6851028682723034988">"idivayisi"</string>
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
index cc887c3..8d14172 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
@@ -21,6 +21,8 @@
 import static android.companion.AssociationRequest.DEVICE_PROFILE_WATCH;
 import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
 
+import static com.android.companiondevicemanager.CompanionDeviceDiscoveryService.SCAN_RESULTS_OBSERVABLE;
+import static com.android.companiondevicemanager.CompanionDeviceDiscoveryService.TIMEOUT_OBSERVABLE;
 import static com.android.companiondevicemanager.Utils.getApplicationLabel;
 import static com.android.companiondevicemanager.Utils.getHtmlFromResources;
 import static com.android.companiondevicemanager.Utils.prepareResultReceiverForIpc;
@@ -91,10 +93,16 @@
 
     // The flag used to prevent double taps, that may lead to sending several requests for creating
     // an association to CDM.
-    private boolean mAssociationApproved;
+    private boolean mApproved;
+    private boolean mCancelled;
+    // A reference to the device selected by the user, to be sent back to the application via
+    // onActivityResult() after the association is created.
+    private @Nullable DeviceFilterPair<?> mSelectedDevice;
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
+        if (DEBUG) Log.d(TAG, "onCreate()");
+
         super.onCreate(savedInstanceState);
         getWindow().addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
     }
@@ -117,26 +125,13 @@
         // Start discovery services if needed.
         if (!mRequest.isSelfManaged()) {
             CompanionDeviceDiscoveryService.startForRequest(this, mRequest);
+            TIMEOUT_OBSERVABLE.addObserver((o, arg) -> cancel(true));
         }
         // Init UI.
         initUI();
     }
 
     @Override
-    protected void onStop() {
-        super.onStop();
-        if (DEBUG) Log.d(TAG, "onStop(), finishing=" + isFinishing());
-
-        // TODO: handle config changes without cancelling.
-        if (!isFinishing()) {
-            cancel(); // will finish()
-        }
-
-        // mAdapter may be observing - need to remove it.
-        CompanionDeviceDiscoveryService.SCAN_RESULTS_OBSERVABLE.deleteObservers();
-    }
-
-    @Override
     protected void onNewIntent(Intent intent) {
         // Handle another incoming request (while we are not done with the original - mRequest -
         // yet).
@@ -153,6 +148,39 @@
         }
     }
 
+    @Override
+    protected void onStop() {
+        super.onStop();
+        if (DEBUG) Log.d(TAG, "onStop(), finishing=" + isFinishing());
+
+        // TODO: handle config changes without cancelling.
+        if (!isDone()) {
+            cancel(false); // will finish()
+        }
+
+        TIMEOUT_OBSERVABLE.deleteObservers();
+        // mAdapter may also be observing - need to remove it.
+        SCAN_RESULTS_OBSERVABLE.deleteObservers();
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        if (DEBUG) Log.d(TAG, "onDestroy()");
+    }
+
+    @Override
+    public void onBackPressed() {
+        if (DEBUG) Log.d(TAG, "onBackPressed()");
+        super.onBackPressed();
+    }
+
+    @Override
+    public void finish() {
+        if (DEBUG) Log.d(TAG, "finish()", new Exception("Stack Trace Dump"));
+        super.finish();
+    }
+
     private void initUI() {
         if (DEBUG) Log.d(TAG, "initUI(), request=" + mRequest);
 
@@ -164,21 +192,61 @@
         mListView = findViewById(R.id.device_list);
         mListView.setOnItemClickListener((av, iv, position, id) -> onListItemClick(position));
 
-        mButtonAllow = findViewById(R.id.button_allow);
-        mButtonAllow.setOnClickListener(this::onAllowButtonClick);
-
-        findViewById(R.id.button_cancel).setOnClickListener(v -> cancel());
+        mButtonAllow = findViewById(R.id.btn_positive);
+        mButtonAllow.setOnClickListener(this::onPositiveButtonClick);
+        findViewById(R.id.btn_negative).setOnClickListener(this::onNegativeButtonClick);
 
         final CharSequence appLabel = getApplicationLabel(this, mRequest.getPackageName());
         if (mRequest.isSelfManaged()) {
             initUiForSelfManagedAssociation(appLabel);
         } else if (mRequest.isSingleDevice()) {
-            initUiForSingleDevice(appLabel);
+            // TODO(b/211722613)
+            // Treat singleDevice as the multipleDevices for now
+            // initUiForSingleDevice(appLabel);
+            initUiForMultipleDevices(appLabel);
         } else {
             initUiForMultipleDevices(appLabel);
         }
     }
 
+    private void onUserSelectedDevice(@NonNull DeviceFilterPair<?> selectedDevice) {
+        if (mSelectedDevice != null) {
+            if (DEBUG) Log.w(TAG, "Already selected.");
+            return;
+        }
+        mSelectedDevice = requireNonNull(selectedDevice);
+
+        final MacAddress macAddress = selectedDevice.getMacAddress();
+        onAssociationApproved(macAddress);
+    }
+
+    private void onAssociationApproved(@Nullable MacAddress macAddress) {
+        if (isDone()) {
+            if (DEBUG) Log.w(TAG, "Already done: " + (mApproved ? "Approved" : "Cancelled"));
+            return;
+        }
+        mApproved = true;
+
+        if (DEBUG) Log.i(TAG, "onAssociationApproved() macAddress=" + macAddress);
+
+        if (!mRequest.isSelfManaged()) {
+            requireNonNull(macAddress);
+            CompanionDeviceDiscoveryService.stop(this);
+        }
+
+        final Bundle data = new Bundle();
+        data.putParcelable(EXTRA_ASSOCIATION_REQUEST, mRequest);
+        data.putBinder(EXTRA_APPLICATION_CALLBACK, mAppCallback.asBinder());
+        if (macAddress != null) {
+            data.putParcelable(EXTRA_MAC_ADDRESS, macAddress);
+        }
+
+        data.putParcelable(EXTRA_RESULT_RECEIVER,
+                prepareResultReceiverForIpc(mOnAssociationCreatedReceiver));
+
+        mCdmServiceReceiver.send(RESULT_CODE_ASSOCIATION_APPROVED, data);
+    }
+
     private void onAssociationCreated(@NonNull AssociationInfo association) {
         if (DEBUG) Log.i(TAG, "onAssociationCreated(), association=" + association);
 
@@ -186,17 +254,26 @@
         setResultAndFinish(association);
     }
 
-    private void cancel() {
-        if (DEBUG) Log.i(TAG, "cancel()");
+    private void cancel(boolean discoveryTimeout) {
+        if (DEBUG) {
+            Log.i(TAG, "cancel(), discoveryTimeout=" + discoveryTimeout,
+                    new Exception("Stack Trace Dump"));
+        }
+
+        if (isDone()) {
+            if (DEBUG) Log.w(TAG, "Already done: " + (mApproved ? "Approved" : "Cancelled"));
+            return;
+        }
+        mCancelled = true;
 
         // Stop discovery service if it was used.
-        if (!mRequest.isSelfManaged()) {
+        if (!mRequest.isSelfManaged() || discoveryTimeout) {
             CompanionDeviceDiscoveryService.stop(this);
         }
 
         // First send callback to the app directly...
         try {
-            mAppCallback.onFailure("Cancelled.");
+            mAppCallback.onFailure(discoveryTimeout ? "Timeout." : "Cancelled.");
         } catch (RemoteException ignore) {
         }
 
@@ -211,8 +288,7 @@
         if (association != null) {
             data.putExtra(CompanionDeviceManager.EXTRA_ASSOCIATION, association);
             if (!association.isSelfManaged()) {
-                data.putExtra(CompanionDeviceManager.EXTRA_DEVICE,
-                        association.getDeviceMacAddressAsString());
+                data.putExtra(CompanionDeviceManager.EXTRA_DEVICE, mSelectedDevice.getDevice());
             }
         }
         setResult(association != null ? RESULT_OK : RESULT_CANCELED, data);
@@ -297,7 +373,7 @@
         mSummary.setText(summary);
 
         mAdapter = new DeviceListAdapter(this);
-        CompanionDeviceDiscoveryService.SCAN_RESULTS_OBSERVABLE.addObserver(mAdapter);
+        SCAN_RESULTS_OBSERVABLE.addObserver(mAdapter);
         // TODO: hide the list and show a spinner until a first device matching device is found.
         mListView.setAdapter(mAdapter);
 
@@ -309,49 +385,35 @@
         if (DEBUG) Log.d(TAG, "onListItemClick() " + position);
 
         final DeviceFilterPair<?> selectedDevice = mAdapter.getItem(position);
-        final MacAddress macAddress = selectedDevice.getMacAddress();
-        onAssociationApproved(macAddress);
+        onUserSelectedDevice(selectedDevice);
     }
 
-    private void onAllowButtonClick(View v) {
-        if (DEBUG) Log.d(TAG, "onAllowButtonClick()");
+    private void onPositiveButtonClick(View v) {
+        if (DEBUG) Log.d(TAG, "on_Positive_ButtonClick()");
 
         // Disable the button, to prevent more clicks.
         v.setEnabled(false);
 
-        final MacAddress macAddress;
         if (mRequest.isSelfManaged()) {
-            macAddress = null;
+            onAssociationApproved(null);
         } else {
-            // TODO: implement.
+            // TODO(b/211722613): call onUserSelectedDevice().
             throw new UnsupportedOperationException(
                     "isSingleDevice() requests are not supported yet.");
         }
-        onAssociationApproved(macAddress);
     }
 
-    private void onAssociationApproved(@Nullable MacAddress macAddress) {
-        if (mAssociationApproved) return;
-        mAssociationApproved = true;
+    private void onNegativeButtonClick(View v) {
+        if (DEBUG) Log.d(TAG, "on_Negative_ButtonClick()");
 
-        if (DEBUG) Log.i(TAG, "onAssociationApproved() macAddress=" + macAddress);
+        // Disable the button, to prevent more clicks.
+        v.setEnabled(false);
 
-        if (!mRequest.isSelfManaged()) {
-            requireNonNull(macAddress);
-            CompanionDeviceDiscoveryService.stop(this);
-        }
+        cancel(false);
+    }
 
-        final Bundle data = new Bundle();
-        data.putParcelable(EXTRA_ASSOCIATION_REQUEST, mRequest);
-        data.putBinder(EXTRA_APPLICATION_CALLBACK, mAppCallback.asBinder());
-        if (macAddress != null) {
-            data.putParcelable(EXTRA_MAC_ADDRESS, macAddress);
-        }
-
-        data.putParcelable(EXTRA_RESULT_RECEIVER,
-                prepareResultReceiverForIpc(mOnAssociationCreatedReceiver));
-
-        mCdmServiceReceiver.send(RESULT_CODE_ASSOCIATION_APPROVED, data);
+    private boolean isDone() {
+        return mApproved || mCancelled;
     }
 
     private final ResultReceiver mOnAssociationCreatedReceiver =
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java
index a4ff1dc..f859130 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java
@@ -22,6 +22,8 @@
 import static com.android.internal.util.CollectionUtils.find;
 import static com.android.internal.util.CollectionUtils.map;
 
+import static java.lang.Math.max;
+import static java.lang.Math.min;
 import static java.util.Objects.requireNonNull;
 
 import android.annotation.MainThread;
@@ -50,6 +52,7 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Parcelable;
+import android.os.SystemProperties;
 import android.text.TextUtils;
 import android.util.Log;
 
@@ -64,13 +67,17 @@
     private static final boolean DEBUG = false;
     private static final String TAG = CompanionDeviceDiscoveryService.class.getSimpleName();
 
+    private static final String SYS_PROP_DEBUG_TIMEOUT = "debug.cdm.discovery_timeout";
+    private static final long TIMEOUT_DEFAULT = 20_000L; // 20 seconds
+    private static final long TIMEOUT_MIN = 1_000L; // 1 sec
+    private static final long TIMEOUT_MAX = 60_000L; // 1 min
+
     private static final String ACTION_START_DISCOVERY =
             "com.android.companiondevicemanager.action.START_DISCOVERY";
     private static final String ACTION_STOP_DISCOVERY =
             "com.android.companiondevicemanager.action.ACTION_STOP_DISCOVERY";
     private static final String EXTRA_ASSOCIATION_REQUEST = "association_request";
 
-    private static final long SCAN_TIMEOUT = 20_000L; // 20 seconds
 
     // TODO: replace with LiveData-s?
     static final Observable TIMEOUT_OBSERVABLE = new MyObservable();
@@ -180,8 +187,7 @@
         // Start BLE scanning (if needed)
         mBleScanCallback = startBleScanningIfNeeded(bleFilters, forceStartScanningAll);
 
-        // Schedule a time-out.
-        Handler.getMain().postDelayed(mTimeoutRunnable, SCAN_TIMEOUT);
+        scheduleTimeout();
     }
 
     @MainThread
@@ -338,6 +344,21 @@
         });
     }
 
+    private void scheduleTimeout() {
+        long timeout = SystemProperties.getLong(SYS_PROP_DEBUG_TIMEOUT, -1);
+        if (timeout <= 0) {
+            // 0 or negative values indicate that the sysprop was never set or should be ignored.
+            timeout = TIMEOUT_DEFAULT;
+        } else {
+            timeout = min(timeout, TIMEOUT_MAX); // should be <= 1 min (TIMEOUT_MAX)
+            timeout = max(timeout, TIMEOUT_MIN); // should be >= 1 sec (TIMEOUT_MIN)
+        }
+
+        if (DEBUG) Log.d(TAG, "scheduleTimeout(), timeout=" + timeout);
+
+        Handler.getMain().postDelayed(mTimeoutRunnable, timeout);
+    }
+
     private void timeout() {
         if (DEBUG) Log.i(TAG, "timeout()");
         stopDiscoveryAndFinish();
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceListAdapter.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceListAdapter.java
index cf2a2bf..2499cf0 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceListAdapter.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceListAdapter.java
@@ -16,18 +16,14 @@
 
 package com.android.companiondevicemanager;
 
-import android.annotation.ColorInt;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.graphics.Color;
-import android.graphics.drawable.Drawable;
-import android.util.TypedValue;
+import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.BaseAdapter;
+import android.widget.ImageView;
 import android.widget.TextView;
 
 import java.util.List;
@@ -39,51 +35,12 @@
  */
 class DeviceListAdapter extends BaseAdapter implements Observer {
     private final Context mContext;
-    private final Resources mResources;
-
-    private final Drawable mBluetoothIcon;
-    private final Drawable mWifiIcon;
-
-    private final @ColorInt int mTextColor;
 
     // List if pairs (display name, address)
     private List<DeviceFilterPair<?>> mDevices;
 
     DeviceListAdapter(Context context) {
         mContext = context;
-        mResources = context.getResources();
-        mBluetoothIcon = getTintedIcon(mResources, android.R.drawable.stat_sys_data_bluetooth);
-        mWifiIcon = getTintedIcon(mResources, com.android.internal.R.drawable.ic_wifi_signal_3);
-        mTextColor = getColor(context, android.R.attr.colorForeground);
-    }
-
-    @Override
-    public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
-        final TextView view = convertView != null ? (TextView) convertView : newView();
-        bind(view, getItem(position));
-        return view;
-    }
-
-    private void bind(TextView textView, DeviceFilterPair<?> item) {
-        textView.setText(item.getDisplayName());
-        textView.setBackgroundColor(Color.TRANSPARENT);
-        /*
-        textView.setCompoundDrawablesWithIntrinsicBounds(
-                item.getDevice() instanceof android.net.wifi.ScanResult
-                        ? mWifiIcon
-                        : mBluetoothIcon,
-                null, null, null);
-        textView.getCompoundDrawables()[0].setTint(mTextColor);
-         */
-    }
-
-    private TextView newView() {
-        final TextView textView = new TextView(mContext);
-        textView.setTextColor(mTextColor);
-        final int padding = 24;
-        textView.setPadding(padding, padding, padding, padding);
-        //textView.setCompoundDrawablePadding(padding);
-        return textView;
     }
 
     @Override
@@ -107,17 +64,29 @@
         notifyDataSetChanged();
     }
 
-    private @ColorInt int getColor(Context context, int attr) {
-        final TypedArray a = context.obtainStyledAttributes(new TypedValue().data,
-                new int[] { attr });
-        final int color = a.getColor(0, 0);
-        a.recycle();
-        return color;
+    @Override
+    public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
+        final View view = convertView != null
+                ? convertView
+                : LayoutInflater.from(mContext).inflate(R.layout.list_item_device, parent, false);
+
+        final DeviceFilterPair<?> item = getItem(position);
+        bindView(view, item);
+
+        return view;
     }
 
-    private static Drawable getTintedIcon(Resources resources, int drawableRes) {
-        Drawable icon = resources.getDrawable(drawableRes, null);
-        icon.setTint(Color.DKGRAY);
-        return icon;
+    private void bindView(@NonNull View view, DeviceFilterPair<?> item) {
+        final TextView textView = view.findViewById(android.R.id.text1);
+        textView.setText(item.getDisplayName());
+
+        final ImageView iconView = view.findViewById(android.R.id.icon);
+
+        // TODO(b/211417476): Set either Bluetooth or WiFi icon.
+        iconView.setVisibility(View.GONE);
+        // final int iconRes = isBt ? android.R.drawable.stat_sys_data_bluetooth
+        //        : com.android.internal.R.drawable.ic_wifi_signal_3;
+        // final Drawable icon = getTintedIcon(mResources, iconRes);
+        // iconView.setImageDrawable(icon);
     }
 }
diff --git a/packages/ConnectivityT/framework-t/Android.bp b/packages/ConnectivityT/framework-t/Android.bp
index 0bda923..38bac1c 100644
--- a/packages/ConnectivityT/framework-t/Android.bp
+++ b/packages/ConnectivityT/framework-t/Android.bp
@@ -150,8 +150,18 @@
         ":framework-connectivity-ethernet-sources",
         ":framework-connectivity-ipsec-sources",
         ":framework-connectivity-netstats-sources",
+    ],
+    visibility: ["//frameworks/base"],
+}
+
+filegroup {
+    name: "framework-connectivity-tiramisu-updatable-sources",
+    srcs: [
         ":framework-connectivity-nsd-sources",
         ":framework-connectivity-tiramisu-internal-sources",
     ],
-    visibility: ["//frameworks/base"],
+    visibility: [
+        "//frameworks/base",
+        "//packages/modules/Connectivity:__subpackages__",
+    ],
 }
diff --git a/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStats.java b/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStats.java
index 216a4a0..f684a4d 100644
--- a/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStats.java
+++ b/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStats.java
@@ -24,13 +24,15 @@
 import android.net.NetworkTemplate;
 import android.net.TrafficStats;
 import android.os.RemoteException;
-import android.util.IntArray;
 import android.util.Log;
 
+import com.android.net.module.util.CollectionUtils;
+
 import dalvik.system.CloseGuard;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
 
 /**
  * Class providing enumeration over buckets of network usage statistics. {@link NetworkStats} objects
@@ -568,7 +570,7 @@
         //       the filtering logic below can be removed.
         int[] uids = mSession.getRelevantUids();
         // Filtering of uids with empty history.
-        IntArray filteredUids = new IntArray(uids.length);
+        final ArrayList<Integer> filteredUids = new ArrayList<>();
         for (int uid : uids) {
             try {
                 NetworkStatsHistory history = mSession.getHistoryIntervalForUid(mTemplate, uid,
@@ -581,7 +583,7 @@
                 Log.w(TAG, "Error while getting history of uid " + uid, e);
             }
         }
-        mUids = filteredUids.toArray();
+        mUids = CollectionUtils.toIntArray(filteredUids);
         mUidOrUidIndex = -1;
         stepHistory();
     }
diff --git a/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java b/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java
index ca83309..a316b8a 100644
--- a/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java
+++ b/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java
@@ -47,7 +47,6 @@
 import android.os.RemoteException;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
-import android.util.DataUnit;
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -119,7 +118,7 @@
      * is reached.
      * @hide
      */
-    public static final long MIN_THRESHOLD_BYTES = DataUnit.MEBIBYTES.toBytes(2);
+    public static final long MIN_THRESHOLD_BYTES = 2 * 1_048_576L; // 2MiB
 
     private final Context mContext;
     private final INetworkStatsService mService;
@@ -139,6 +138,7 @@
         mContext = context;
         mService = service;
         setPollOnOpen(true);
+        setAugmentWithSubscriptionPlan(true);
     }
 
     /** @hide */
@@ -170,16 +170,44 @@
         }
     }
 
-    /** @hide */
-    public Bucket querySummaryForDevice(NetworkTemplate template,
-            long startTime, long endTime) throws SecurityException, RemoteException {
-        Bucket bucket = null;
-        NetworkStats stats = new NetworkStats(mContext, template, mFlags, startTime, endTime,
-                mService);
-        bucket = stats.getDeviceSummaryForNetwork();
-
-        stats.close();
-        return bucket;
+    /**
+     * Query network usage statistics summaries.
+     *
+     * Result is summarised data usage for the whole
+     * device. Result is a single Bucket aggregated over time, state, uid, tag, metered, and
+     * roaming. This means the bucket's start and end timestamp will be the same as the
+     * 'startTime' and 'endTime' arguments. State is going to be
+     * {@link NetworkStats.Bucket#STATE_ALL}, uid {@link NetworkStats.Bucket#UID_ALL},
+     * tag {@link NetworkStats.Bucket#TAG_NONE},
+     * default network {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL},
+     * metered {@link NetworkStats.Bucket#METERED_ALL},
+     * and roaming {@link NetworkStats.Bucket#ROAMING_ALL}.
+     * This may take a long time, and apps should avoid calling this on their main thread.
+     *
+     * @param template Template used to match networks. See {@link NetworkTemplate}.
+     * @param startTime Start of period, in milliseconds since the Unix epoch, see
+     *            {@link java.lang.System#currentTimeMillis}.
+     * @param endTime End of period, in milliseconds since the Unix epoch, see
+     *            {@link java.lang.System#currentTimeMillis}.
+     * @return Bucket Summarised data usage.
+     *
+     * @hide
+     */
+    @NonNull
+    @WorkerThread
+    // @SystemApi(client = MODULE_LIBRARIES)
+    public Bucket querySummaryForDevice(@NonNull NetworkTemplate template,
+            long startTime, long endTime) {
+        try {
+            NetworkStats stats =
+                    new NetworkStats(mContext, template, mFlags, startTime, endTime, mService);
+            Bucket bucket = stats.getDeviceSummaryForNetwork();
+            stats.close();
+            return bucket;
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+        return null; // To make the compiler happy.
     }
 
     /**
@@ -323,14 +351,37 @@
         return querySummary(template, startTime, endTime);
     }
 
-    /** @hide */
-    public NetworkStats querySummary(NetworkTemplate template, long startTime,
-            long endTime) throws SecurityException, RemoteException {
-        NetworkStats result;
-        result = new NetworkStats(mContext, template, mFlags, startTime, endTime, mService);
-        result.startSummaryEnumeration();
-
-        return result;
+    /**
+     * Query network usage statistics summaries.
+     *
+     * The results will only include traffic made by UIDs belonging to the calling user profile.
+     * The results are aggregated over time, so that all buckets will have the same start and
+     * end timestamps as the passed arguments. Not aggregated over state, uid, default network,
+     * metered, or roaming.
+     * This may take a long time, and apps should avoid calling this on their main thread.
+     *
+     * @param template Template used to match networks. See {@link NetworkTemplate}.
+     * @param startTime Start of period, in milliseconds since the Unix epoch, see
+     *            {@link java.lang.System#currentTimeMillis}.
+     * @param endTime End of period, in milliseconds since the Unix epoch, see
+     *            {@link java.lang.System#currentTimeMillis}.
+     * @return Statistics which is described above.
+     * @hide
+     */
+    @Nullable
+    // @SystemApi(client = MODULE_LIBRARIES)
+    @WorkerThread
+    public NetworkStats querySummary(@NonNull NetworkTemplate template, long startTime,
+            long endTime) throws SecurityException {
+        try {
+            NetworkStats result =
+                    new NetworkStats(mContext, template, mFlags, startTime, endTime, mService);
+            result.startSummaryEnumeration();
+            return result;
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+        return null; // To make the compiler happy.
     }
 
     /**
diff --git a/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java b/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java
index 7cd63ef..ece54df 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java
@@ -16,7 +16,9 @@
 
 package android.net;
 
+import android.annotation.CallbackExecutor;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
@@ -32,6 +34,7 @@
 import java.util.ArrayList;
 import java.util.Objects;
 import java.util.concurrent.Executor;
+import java.util.function.BiConsumer;
 
 /**
  * A class representing the IP configuration of the Ethernet network.
@@ -315,4 +318,83 @@
         }
         return new TetheredInterfaceRequest(mService, cbInternal);
     }
+
+    private static final class InternalNetworkManagementListener
+            extends IInternalNetworkManagementListener.Stub {
+        @NonNull
+        private final Executor mExecutor;
+        @NonNull
+        private final BiConsumer<Network, InternalNetworkManagementException> mListener;
+
+        InternalNetworkManagementListener(
+                @NonNull final Executor executor,
+                @NonNull final BiConsumer<Network, InternalNetworkManagementException> listener) {
+            Objects.requireNonNull(executor, "Pass a non-null executor");
+            Objects.requireNonNull(listener, "Pass a non-null listener");
+            mExecutor = executor;
+            mListener = listener;
+        }
+
+        @Override
+        public void onComplete(
+                @Nullable final Network network,
+                @Nullable final InternalNetworkManagementException e) {
+            mExecutor.execute(() -> mListener.accept(network, e));
+        }
+    }
+
+    private InternalNetworkManagementListener getInternalNetworkManagementListener(
+            @Nullable final Executor executor,
+            @Nullable final BiConsumer<Network, InternalNetworkManagementException> listener) {
+        if (null != listener) {
+            Objects.requireNonNull(executor, "Pass a non-null executor, or a null listener");
+        }
+        final InternalNetworkManagementListener proxy;
+        if (null == listener) {
+            proxy = null;
+        } else {
+            proxy = new InternalNetworkManagementListener(executor, listener);
+        }
+        return proxy;
+    }
+
+    private void updateConfiguration(
+            @NonNull String iface,
+            @NonNull InternalNetworkUpdateRequest request,
+            @Nullable @CallbackExecutor Executor executor,
+            @Nullable BiConsumer<Network, InternalNetworkManagementException> listener) {
+        final InternalNetworkManagementListener proxy = getInternalNetworkManagementListener(
+                executor, listener);
+        try {
+            mService.updateConfiguration(iface, request, proxy);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    private void connectNetwork(
+            @NonNull String iface,
+            @Nullable @CallbackExecutor Executor executor,
+            @Nullable BiConsumer<Network, InternalNetworkManagementException> listener) {
+        final InternalNetworkManagementListener proxy = getInternalNetworkManagementListener(
+                executor, listener);
+        try {
+            mService.connectNetwork(iface, proxy);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    private void disconnectNetwork(
+            @NonNull String iface,
+            @Nullable @CallbackExecutor Executor executor,
+            @Nullable BiConsumer<Network, InternalNetworkManagementException> listener) {
+        final InternalNetworkManagementListener proxy = getInternalNetworkManagementListener(
+                executor, listener);
+        try {
+            mService.disconnectNetwork(iface, proxy);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
 }
diff --git a/packages/ConnectivityT/framework-t/src/android/net/IEthernetManager.aidl b/packages/ConnectivityT/framework-t/src/android/net/IEthernetManager.aidl
index e058e5a..e688bea 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/IEthernetManager.aidl
+++ b/packages/ConnectivityT/framework-t/src/android/net/IEthernetManager.aidl
@@ -18,6 +18,8 @@
 
 import android.net.IpConfiguration;
 import android.net.IEthernetServiceListener;
+import android.net.IInternalNetworkManagementListener;
+import android.net.InternalNetworkUpdateRequest;
 import android.net.ITetheredInterfaceCallback;
 
 /**
@@ -36,4 +38,8 @@
     void setIncludeTestInterfaces(boolean include);
     void requestTetheredInterface(in ITetheredInterfaceCallback callback);
     void releaseTetheredInterface(in ITetheredInterfaceCallback callback);
+    void updateConfiguration(String iface, in InternalNetworkUpdateRequest request,
+        in IInternalNetworkManagementListener listener);
+    void connectNetwork(String iface, in IInternalNetworkManagementListener listener);
+    void disconnectNetwork(String iface, in IInternalNetworkManagementListener listener);
 }
diff --git a/packages/ConnectivityT/framework-t/src/android/net/IpSecManager.java b/packages/ConnectivityT/framework-t/src/android/net/IpSecManager.java
index 8376299..0d15dff 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/IpSecManager.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/IpSecManager.java
@@ -17,8 +17,6 @@
 
 import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
 
-import static com.android.internal.util.Preconditions.checkNotNull;
-
 import android.annotation.NonNull;
 import android.annotation.RequiresFeature;
 import android.annotation.RequiresPermission;
@@ -46,6 +44,7 @@
 import java.net.DatagramSocket;
 import java.net.InetAddress;
 import java.net.Socket;
+import java.util.Objects;
 
 /**
  * This class contains methods for managing IPsec sessions. Once configured, the kernel will apply
@@ -86,6 +85,7 @@
      *
      * @hide
      */
+    @SystemApi(client = MODULE_LIBRARIES)
     public static final int DIRECTION_FWD = 2;
 
     /**
@@ -988,7 +988,7 @@
      */
     public IpSecManager(Context ctx, IIpSecService service) {
         mContext = ctx;
-        mService = checkNotNull(service, "missing service");
+        mService = Objects.requireNonNull(service, "missing service");
     }
 
     private static void maybeHandleServiceSpecificException(ServiceSpecificException sse) {
diff --git a/packages/ConnectivityT/framework-t/src/android/net/IpSecTransform.java b/packages/ConnectivityT/framework-t/src/android/net/IpSecTransform.java
index b48c1fd..36199a0 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/IpSecTransform.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/IpSecTransform.java
@@ -33,7 +33,6 @@
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.Preconditions;
 
 import dalvik.system.CloseGuard;
 
@@ -41,6 +40,7 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.net.InetAddress;
+import java.util.Objects;
 
 /**
  * This class represents a transform, which roughly corresponds to an IPsec Security Association.
@@ -255,7 +255,7 @@
         @NonNull
         public IpSecTransform.Builder setEncryption(@NonNull IpSecAlgorithm algo) {
             // TODO: throw IllegalArgumentException if algo is not an encryption algorithm.
-            Preconditions.checkNotNull(algo);
+            Objects.requireNonNull(algo);
             mConfig.setEncryption(algo);
             return this;
         }
@@ -270,7 +270,7 @@
         @NonNull
         public IpSecTransform.Builder setAuthentication(@NonNull IpSecAlgorithm algo) {
             // TODO: throw IllegalArgumentException if algo is not an authentication algorithm.
-            Preconditions.checkNotNull(algo);
+            Objects.requireNonNull(algo);
             mConfig.setAuthentication(algo);
             return this;
         }
@@ -290,7 +290,7 @@
          */
         @NonNull
         public IpSecTransform.Builder setAuthenticatedEncryption(@NonNull IpSecAlgorithm algo) {
-            Preconditions.checkNotNull(algo);
+            Objects.requireNonNull(algo);
             mConfig.setAuthenticatedEncryption(algo);
             return this;
         }
@@ -311,7 +311,7 @@
         @NonNull
         public IpSecTransform.Builder setIpv4Encapsulation(
                 @NonNull IpSecManager.UdpEncapsulationSocket localSocket, int remotePort) {
-            Preconditions.checkNotNull(localSocket);
+            Objects.requireNonNull(localSocket);
             mConfig.setEncapType(ENCAP_ESPINUDP);
             if (localSocket.getResourceId() == INVALID_RESOURCE_ID) {
                 throw new IllegalArgumentException("Invalid UdpEncapsulationSocket");
@@ -348,8 +348,8 @@
                 @NonNull IpSecManager.SecurityParameterIndex spi)
                 throws IpSecManager.ResourceUnavailableException,
                         IpSecManager.SpiUnavailableException, IOException {
-            Preconditions.checkNotNull(sourceAddress);
-            Preconditions.checkNotNull(spi);
+            Objects.requireNonNull(sourceAddress);
+            Objects.requireNonNull(spi);
             if (spi.getResourceId() == INVALID_RESOURCE_ID) {
                 throw new IllegalArgumentException("Invalid SecurityParameterIndex");
             }
@@ -387,8 +387,8 @@
                 @NonNull IpSecManager.SecurityParameterIndex spi)
                 throws IpSecManager.ResourceUnavailableException,
                         IpSecManager.SpiUnavailableException, IOException {
-            Preconditions.checkNotNull(sourceAddress);
-            Preconditions.checkNotNull(spi);
+            Objects.requireNonNull(sourceAddress);
+            Objects.requireNonNull(spi);
             if (spi.getResourceId() == INVALID_RESOURCE_ID) {
                 throw new IllegalArgumentException("Invalid SecurityParameterIndex");
             }
@@ -404,7 +404,7 @@
          * @param context current context
          */
         public Builder(@NonNull Context context) {
-            Preconditions.checkNotNull(context);
+            Objects.requireNonNull(context);
             mContext = context;
             mConfig = new IpSecConfig();
         }
diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentity.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentity.java
index eb8f43e..8f1115e 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentity.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentity.java
@@ -21,7 +21,6 @@
 import android.annotation.Nullable;
 import android.content.Context;
 import android.net.wifi.WifiInfo;
-import android.net.wifi.WifiManager;
 import android.service.NetworkIdentityProto;
 import android.telephony.Annotation.NetworkType;
 import android.util.proto.ProtoOutputStream;
@@ -228,11 +227,11 @@
         final int oemManaged = getOemBitfield(snapshot.getNetworkCapabilities());
 
         if (legacyType == TYPE_WIFI) {
-            networkId = snapshot.getNetworkCapabilities().getSsid();
-            if (networkId == null) {
-                final WifiManager wifi = context.getSystemService(WifiManager.class);
-                final WifiInfo info = wifi.getConnectionInfo();
-                networkId = info != null ? info.getSSID() : null;
+            final TransportInfo transportInfo = snapshot.getNetworkCapabilities()
+                    .getTransportInfo();
+            if (transportInfo instanceof WifiInfo) {
+                final WifiInfo info = (WifiInfo) transportInfo;
+                networkId = info != null ? info.getCurrentNetworkKey() : null;
             }
         }
 
diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkStats.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkStats.java
index c7ffc19..b00fea4 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/NetworkStats.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/NetworkStats.java
@@ -16,7 +16,7 @@
 
 package android.net;
 
-import static com.android.internal.net.NetworkUtilsInternal.multiplySafeByRational;
+import static com.android.net.module.util.NetworkStatsUtils.multiplySafeByRational;
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
@@ -31,7 +31,7 @@
 import android.util.SparseBooleanArray;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.ArrayUtils;
+import com.android.net.module.util.CollectionUtils;
 
 import libcore.util.EmptyArray;
 
@@ -83,10 +83,7 @@
      */
     // TODO: Rename TAG_ALL to TAG_ANY.
     public static final int TAG_ALL = -1;
-    /**
-     * {@link #set} value for all sets combined, not including debug sets.
-     * @hide
-     */
+    /** {@link #set} value for all sets combined, not including debug sets. */
     public static final int SET_ALL = -1;
     /** {@link #set} value where background data is accounted. */
     public static final int SET_DEFAULT = 0;
@@ -114,9 +111,6 @@
             SET_ALL,
             SET_DEFAULT,
             SET_FOREGROUND,
-            SET_DEBUG_START,
-            SET_DBG_VPN_IN,
-            SET_DBG_VPN_OUT
     })
     public @interface State {
     }
@@ -131,10 +125,7 @@
     // TODO: Rename TAG_NONE to TAG_ALL.
     public static final int TAG_NONE = 0;
 
-    /**
-     * {@link #metered} value to account for all metered states.
-     * @hide
-     */
+    /** {@link #metered} value to account for all metered states. */
     public static final int METERED_ALL = -1;
     /** {@link #metered} value where native, unmetered data is accounted. */
     public static final int METERED_NO = 0;
@@ -152,10 +143,7 @@
     }
 
 
-    /**
-     * {@link #roaming} value to account for all roaming states.
-     * @hide
-     */
+    /** {@link #roaming} value to account for all roaming states. */
     public static final int ROAMING_ALL = -1;
     /** {@link #roaming} value where native, non-roaming data is accounted. */
     public static final int ROAMING_NO = 0;
@@ -172,10 +160,7 @@
     public @interface Roaming {
     }
 
-    /**
-     * {@link #onDefaultNetwork} value to account for all default network states.
-     * @hide
-     */
+    /** {@link #onDefaultNetwork} value to account for all default network states. */
     public static final int DEFAULT_NETWORK_ALL = -1;
     /** {@link #onDefaultNetwork} value to account for usage while not the default network. */
     public static final int DEFAULT_NETWORK_NO = 0;
@@ -1185,7 +1170,7 @@
      * @hide
      */
     public void removeUids(int[] uids) {
-        filter(e -> !ArrayUtils.contains(uids, e.uid));
+        filter(e -> !CollectionUtils.contains(uids, e.uid));
     }
 
     /**
@@ -1218,7 +1203,7 @@
         filter(e -> (limitUid == UID_ALL || limitUid == e.uid)
                 && (limitTag == TAG_ALL || limitTag == e.tag)
                 && (limitIfaces == INTERFACES_ALL
-                    || ArrayUtils.contains(limitIfaces, e.iface)));
+                    || CollectionUtils.contains(limitIfaces, e.iface)));
     }
 
     /**
diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsAccess.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsAccess.java
index 3885a9e..b64fbdb 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsAccess.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsAccess.java
@@ -17,6 +17,7 @@
 package android.net;
 
 import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.net.NetworkStats.UID_ALL;
 import static android.net.TrafficStats.UID_REMOVED;
 import static android.net.TrafficStats.UID_TETHERING;
@@ -24,7 +25,7 @@
 import android.Manifest;
 import android.annotation.IntDef;
 import android.app.AppOpsManager;
-import android.app.admin.DevicePolicyManagerInternal;
+import android.app.admin.DevicePolicyManager;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.os.Binder;
@@ -32,8 +33,6 @@
 import android.os.UserHandle;
 import android.telephony.TelephonyManager;
 
-import com.android.server.LocalServices;
-
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
@@ -108,9 +107,8 @@
 
     /** Returns the {@link NetworkStatsAccess.Level} for the given caller. */
     public static @NetworkStatsAccess.Level int checkAccessLevel(
-            Context context, int callingUid, String callingPackage) {
-        final DevicePolicyManagerInternal dpmi = LocalServices.getService(
-                DevicePolicyManagerInternal.class);
+            Context context, int callingPid, int callingUid, String callingPackage) {
+        final DevicePolicyManager mDpm = context.getSystemService(DevicePolicyManager.class);
         final TelephonyManager tm = (TelephonyManager)
                 context.getSystemService(Context.TELEPHONY_SERVICE);
         boolean hasCarrierPrivileges;
@@ -123,10 +121,15 @@
             Binder.restoreCallingIdentity(token);
         }
 
-        final boolean isDeviceOwner = dpmi != null && dpmi.isActiveDeviceOwner(callingUid);
+        final boolean isDeviceOwner = mDpm != null && mDpm.isDeviceOwnerApp(callingPackage);
         final int appId = UserHandle.getAppId(callingUid);
+
+        final boolean isNetworkStack = context.checkPermission(
+                android.Manifest.permission.NETWORK_STACK, callingPid, callingUid)
+                == PERMISSION_GRANTED;
+
         if (hasCarrierPrivileges || isDeviceOwner
-                || appId == Process.SYSTEM_UID || appId == Process.NETWORK_STACK_UID) {
+                || appId == Process.SYSTEM_UID || isNetworkStack) {
             // Carrier-privileged apps and device owners, and the system (including the
             // network stack) can access data usage for all apps on the device.
             return NetworkStatsAccess.Level.DEVICE;
@@ -139,8 +142,8 @@
         }
 
         //TODO(b/169395065) Figure out if this flow makes sense in Device Owner mode.
-        boolean isProfileOwner = dpmi != null && (dpmi.isActiveProfileOwner(callingUid)
-                || dpmi.isActiveDeviceOwner(callingUid));
+        boolean isProfileOwner = mDpm != null && (mDpm.isProfileOwnerApp(callingPackage)
+                || mDpm.isDeviceOwnerApp(callingPackage));
         if (isProfileOwner) {
             // Apps with the AppOps permission, profile owners, and apps with the privileged
             // permission can access data usage for all apps in this user/profile.
@@ -157,6 +160,8 @@
      */
     public static boolean isAccessibleToUser(int uid, int callerUid,
             @NetworkStatsAccess.Level int accessLevel) {
+        final int userId = UserHandle.getUserHandleForUid(uid).getIdentifier();
+        final int callerUserId = UserHandle.getUserHandleForUid(callerUid).getIdentifier();
         switch (accessLevel) {
             case NetworkStatsAccess.Level.DEVICE:
                 // Device-level access - can access usage for any uid.
@@ -167,13 +172,13 @@
                 // anonymized uids
                 return uid == android.os.Process.SYSTEM_UID || uid == UID_REMOVED
                         || uid == UID_TETHERING || uid == UID_ALL
-                        || UserHandle.getUserId(uid) == UserHandle.getUserId(callerUid);
+                        || userId == callerUserId;
             case NetworkStatsAccess.Level.USER:
                 // User-level access - can access usage for any app running in the same user, along
                 // with some special uids (system, removed, or tethering).
                 return uid == android.os.Process.SYSTEM_UID || uid == UID_REMOVED
                         || uid == UID_TETHERING
-                        || UserHandle.getUserId(uid) == UserHandle.getUserId(callerUid);
+                        || userId == callerUserId;
             case NetworkStatsAccess.Level.DEFAULT:
             default:
                 // Default access level - can only access one's own usage.
@@ -187,8 +192,8 @@
             AppOpsManager appOps = (AppOpsManager) context.getSystemService(
                     Context.APP_OPS_SERVICE);
 
-            final int mode = appOps.noteOp(AppOpsManager.OP_GET_USAGE_STATS,
-                    callingUid, callingPackage);
+            final int mode = appOps.noteOp(AppOpsManager.OPSTR_GET_USAGE_STATS,
+                    callingUid, callingPackage, null /* attributionTag */, null /* message */);
             if (mode == AppOpsManager.MODE_DEFAULT) {
                 // The default behavior here is to check if PackageManager has given the app
                 // permission.
diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsCollection.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsCollection.java
index 0d3b9ed..7935d28 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsCollection.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsCollection.java
@@ -30,7 +30,7 @@
 import static android.net.TrafficStats.UID_REMOVED;
 import static android.text.format.DateUtils.WEEK_IN_MILLIS;
 
-import static com.android.internal.net.NetworkUtilsInternal.multiplySafeByRational;
+import static com.android.net.module.util.NetworkStatsUtils.multiplySafeByRational;
 
 import android.os.Binder;
 import android.service.NetworkStatsCollectionKeyProto;
@@ -40,21 +40,17 @@
 import android.text.format.DateUtils;
 import android.util.ArrayMap;
 import android.util.AtomicFile;
-import android.util.IntArray;
-import android.util.MathUtils;
+import android.util.IndentingPrintWriter;
+import android.util.Log;
 import android.util.Range;
-import android.util.Slog;
 import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FastDataInput;
 import com.android.internal.util.FastDataOutput;
 import com.android.internal.util.FileRotator;
-import com.android.internal.util.IndentingPrintWriter;
-
-import com.google.android.collect.Lists;
-import com.google.android.collect.Maps;
+import com.android.net.module.util.CollectionUtils;
+import com.android.net.module.util.NetworkStatsUtils;
 
 import libcore.io.IoUtils;
 
@@ -196,11 +192,11 @@
 
     public int[] getRelevantUids(@NetworkStatsAccess.Level int accessLevel,
                 final int callerUid) {
-        IntArray uids = new IntArray();
+        final ArrayList<Integer> uids = new ArrayList<>();
         for (int i = 0; i < mStats.size(); i++) {
             final Key key = mStats.keyAt(i);
             if (NetworkStatsAccess.isAccessibleToUser(key.uid, callerUid, accessLevel)) {
-                int j = uids.binarySearch(key.uid);
+                int j = Collections.binarySearch(uids, new Integer(key.uid));
 
                 if (j < 0) {
                     j = ~j;
@@ -208,7 +204,7 @@
                 }
             }
         }
-        return uids.toArray();
+        return CollectionUtils.toIntArray(uids);
     }
 
     /**
@@ -225,7 +221,8 @@
 
         // 180 days of history should be enough for anyone; if we end up needing
         // more, we'll dynamically grow the history object.
-        final int bucketEstimate = (int) MathUtils.constrain(((end - start) / mBucketDuration), 0,
+        final int bucketEstimate = (int) NetworkStatsUtils.constrain(
+                ((end - start) / mBucketDuration), 0,
                 (180 * DateUtils.DAY_IN_MILLIS) / mBucketDuration);
         final NetworkStatsHistory combined = new NetworkStatsHistory(
                 mBucketDuration, bucketEstimate, fields);
@@ -316,7 +313,7 @@
 
             final long deltaTotal = combined.getTotalBytes() - beforeTotal;
             if (deltaTotal != 0) {
-                Slog.d(TAG, "Augmented network usage by " + deltaTotal + " bytes");
+                Log.d(TAG, "Augmented network usage by " + deltaTotal + " bytes");
             }
 
             // Finally we can slice data as originally requested
@@ -489,11 +486,11 @@
 
     private void write(DataOutput out) throws IOException {
         // cluster key lists grouped by ident
-        final HashMap<NetworkIdentitySet, ArrayList<Key>> keysByIdent = Maps.newHashMap();
+        final HashMap<NetworkIdentitySet, ArrayList<Key>> keysByIdent = new HashMap<>();
         for (Key key : mStats.keySet()) {
             ArrayList<Key> keys = keysByIdent.get(key.ident);
             if (keys == null) {
-                keys = Lists.newArrayList();
+                keys = new ArrayList<>();
                 keysByIdent.put(key.ident, keys);
             }
             keys.add(key);
@@ -640,12 +637,12 @@
      * {@link TrafficStats#UID_REMOVED}.
      */
     public void removeUids(int[] uids) {
-        final ArrayList<Key> knownKeys = Lists.newArrayList();
+        final ArrayList<Key> knownKeys = new ArrayList<>();
         knownKeys.addAll(mStats.keySet());
 
         // migrate all UID stats into special "removed" bucket
         for (Key key : knownKeys) {
-            if (ArrayUtils.contains(uids, key.uid)) {
+            if (CollectionUtils.contains(uids, key.uid)) {
                 // only migrate combined TAG_NONE history
                 if (key.tag == TAG_NONE) {
                     final NetworkStatsHistory uidHistory = mStats.get(key);
@@ -672,7 +669,7 @@
     }
 
     private ArrayList<Key> getSortedKeys() {
-        final ArrayList<Key> keys = Lists.newArrayList();
+        final ArrayList<Key> keys = new ArrayList<>();
         keys.addAll(mStats.keySet());
         Collections.sort(keys);
         return keys;
diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsHistory.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsHistory.java
index a875e1a..428bc6d 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsHistory.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsHistory.java
@@ -28,8 +28,7 @@
 import static android.net.NetworkStatsHistory.ParcelUtils.writeLongArray;
 import static android.text.format.DateUtils.SECOND_IN_MILLIS;
 
-import static com.android.internal.net.NetworkUtilsInternal.multiplySafeByRational;
-import static com.android.internal.util.ArrayUtils.total;
+import static com.android.net.module.util.NetworkStatsUtils.multiplySafeByRational;
 
 import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Build;
@@ -37,10 +36,11 @@
 import android.os.Parcelable;
 import android.service.NetworkStatsHistoryBucketProto;
 import android.service.NetworkStatsHistoryProto;
-import android.util.MathUtils;
+import android.util.IndentingPrintWriter;
 import android.util.proto.ProtoOutputStream;
 
-import com.android.internal.util.IndentingPrintWriter;
+import com.android.net.module.util.CollectionUtils;
+import com.android.net.module.util.NetworkStatsUtils;
 
 import libcore.util.EmptyArray;
 
@@ -174,7 +174,7 @@
                 txPackets = new long[bucketStart.length];
                 operations = new long[bucketStart.length];
                 bucketCount = bucketStart.length;
-                totalBytes = total(rxBytes) + total(txBytes);
+                totalBytes = CollectionUtils.total(rxBytes) + CollectionUtils.total(txBytes);
                 break;
             }
             case VERSION_ADD_PACKETS:
@@ -189,7 +189,7 @@
                 txPackets = readVarLongArray(in);
                 operations = readVarLongArray(in);
                 bucketCount = bucketStart.length;
-                totalBytes = total(rxBytes) + total(txBytes);
+                totalBytes = CollectionUtils.total(rxBytes) + CollectionUtils.total(txBytes);
                 break;
             }
             default: {
@@ -267,7 +267,7 @@
         } else {
             index -= 1;
         }
-        return MathUtils.constrain(index, 0, bucketCount - 1);
+        return NetworkStatsUtils.constrain(index, 0, bucketCount - 1);
     }
 
     /**
@@ -281,7 +281,7 @@
         } else {
             index += 1;
         }
-        return MathUtils.constrain(index, 0, bucketCount - 1);
+        return NetworkStatsUtils.constrain(index, 0, bucketCount - 1);
     }
 
     /**
@@ -349,6 +349,9 @@
 
         // create any buckets needed by this range
         ensureBuckets(start, end);
+        // Return fast if there is still no entry. This would typically happen when the start,
+        // end or duration are not valid values, e.g. start > end, negative duration value, etc.
+        if (bucketCount == 0) return;
 
         // distribute data usage into buckets
         long duration = end - start;
@@ -560,6 +563,9 @@
         entry.txPackets = txPackets != null ? 0 : UNKNOWN;
         entry.operations = operations != null ? 0 : UNKNOWN;
 
+        // Return fast if there is no entry.
+        if (bucketCount == 0) return entry;
+
         final int startIndex = getIndexAfter(end);
         for (int i = startIndex; i >= 0; i--) {
             final long curStart = bucketStart[i];
diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkTemplate.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkTemplate.java
index cb5a025..e9084b0 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/NetworkTemplate.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/NetworkTemplate.java
@@ -16,6 +16,7 @@
 
 package android.net;
 
+import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
 import static android.net.ConnectivityManager.TYPE_BLUETOOTH;
 import static android.net.ConnectivityManager.TYPE_ETHERNET;
 import static android.net.ConnectivityManager.TYPE_MOBILE;
@@ -35,29 +36,36 @@
 import static android.net.NetworkStats.ROAMING_ALL;
 import static android.net.NetworkStats.ROAMING_NO;
 import static android.net.NetworkStats.ROAMING_YES;
-import static android.net.wifi.WifiInfo.sanitizeSsid;
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SystemApi;
 import android.compat.annotation.UnsupportedAppUsage;
+import android.net.wifi.WifiInfo;
 import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.telephony.Annotation.NetworkType;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
+import android.util.ArraySet;
 
-import com.android.internal.util.ArrayUtils;
+import com.android.net.module.util.CollectionUtils;
 import com.android.net.module.util.NetworkIdentityUtils;
+import com.android.net.module.util.NetworkStatsUtils;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.Comparator;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Objects;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
 
 /**
  * Predicate used to match {@link NetworkIdentity}, usually when collecting
@@ -65,7 +73,7 @@
  *
  * @hide
  */
-// @SystemApi(client = MODULE_LIBRARIES)
+@SystemApi(client = MODULE_LIBRARIES)
 public final class NetworkTemplate implements Parcelable {
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
@@ -110,29 +118,18 @@
      */
     public static final int MATCH_CARRIER = 10;
 
+    // TODO: Remove this and replace all callers with WIFI_NETWORK_KEY_ALL.
     /** @hide */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(prefix = { "SUBSCRIBER_ID_MATCH_RULE_" }, value = {
-            SUBSCRIBER_ID_MATCH_RULE_EXACT,
-            SUBSCRIBER_ID_MATCH_RULE_ALL
-    })
-    public @interface SubscriberIdMatchRule{}
-    /**
-     * Value of the match rule of the subscriberId to match networks with specific subscriberId.
-     */
-    public static final int SUBSCRIBER_ID_MATCH_RULE_EXACT = 0;
-    /**
-     * Value of the match rule of the subscriberId to match networks with any subscriberId which
-     * includes null and non-null.
-     */
-    public static final int SUBSCRIBER_ID_MATCH_RULE_ALL = 1;
+    public static final String WIFI_NETWORKID_ALL = null;
 
     /**
-     * Wi-Fi Network ID is never supposed to be null (if it is, it is a bug that
+     * Wi-Fi Network Key is never supposed to be null (if it is, it is a bug that
      * should be fixed), so it's not possible to want to match null vs
-     * non-null. Therefore it's fine to use null as a sentinel for Network ID.
+     * non-null. Therefore it's fine to use null as a sentinel for Wifi Network Key.
+     *
+     * @hide
      */
-    public static final String WIFI_NETWORKID_ALL = null;
+    public static final String WIFI_NETWORK_KEY_ALL = WIFI_NETWORKID_ALL;
 
     /**
      * Include all network types when filtering. This is meant to merge in with the
@@ -219,13 +216,16 @@
     public static NetworkTemplate buildTemplateMobileWithRatType(@Nullable String subscriberId,
             @NetworkType int ratType, int metered) {
         if (TextUtils.isEmpty(subscriberId)) {
-            return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null, null, null,
-                    metered, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL,
-                    SUBSCRIBER_ID_MATCH_RULE_EXACT);
+            return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null /* subscriberId */,
+                    null /* matchSubscriberIds */,
+                    new String[0] /* matchWifiNetworkKeys */, metered, ROAMING_ALL,
+                    DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL,
+                    NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT);
         }
-        return new NetworkTemplate(MATCH_MOBILE, subscriberId, new String[]{subscriberId}, null,
+        return new NetworkTemplate(MATCH_MOBILE, subscriberId, new String[] { subscriberId },
+                new String[0] /* matchWifiNetworkKeys */,
                 metered, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL,
-                SUBSCRIBER_ID_MATCH_RULE_EXACT);
+                NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT);
     }
 
     /**
@@ -241,7 +241,7 @@
 
     /**
      * Template to match all metered {@link ConnectivityManager#TYPE_WIFI} networks,
-     * regardless of SSID.
+     * regardless of key of the wifi network.
      *
      * @hide
      */
@@ -261,31 +261,41 @@
 
     /**
      * Template to match {@link ConnectivityManager#TYPE_WIFI} networks with the
-     * given SSID.
+     * given key of the wifi network.
      *
+     * @param wifiNetworkKey key of the wifi network. see {@link WifiInfo#getCurrentNetworkKey()}
+     *                  to know details about the key.
      * @hide
      */
-    public static NetworkTemplate buildTemplateWifi(@NonNull String networkId) {
-        Objects.requireNonNull(networkId);
+    public static NetworkTemplate buildTemplateWifi(@NonNull String wifiNetworkKey) {
+        Objects.requireNonNull(wifiNetworkKey);
         return new NetworkTemplate(MATCH_WIFI, null /* subscriberId */,
                 new String[] { null } /* matchSubscriberIds */,
-                networkId, METERED_ALL, ROAMING_ALL,
+                new String[] { wifiNetworkKey }, METERED_ALL, ROAMING_ALL,
                 DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL,
-                SUBSCRIBER_ID_MATCH_RULE_ALL);
+                NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_ALL);
     }
 
     /**
-     * Template to match all {@link ConnectivityManager#TYPE_WIFI} networks with the given SSID,
-     * and IMSI.
+     * Template to match all {@link ConnectivityManager#TYPE_WIFI} networks with the given
+     * key of the wifi network and IMSI.
      *
-     * Call with {@link #WIFI_NETWORKID_ALL} for {@code networkId} to get result regardless of SSID.
+     * Call with {@link #WIFI_NETWORK_KEY_ALL} for {@code wifiNetworkKey} to get result regardless
+     * of key of the wifi network.
+     *
+     * @param wifiNetworkKey key of the wifi network. see {@link WifiInfo#getCurrentNetworkKey()}
+     *                  to know details about the key.
+     * @param subscriberId the IMSI associated to this wifi network.
+     *
+     * @hide
      */
-    public static NetworkTemplate buildTemplateWifi(@Nullable String networkId,
+    public static NetworkTemplate buildTemplateWifi(@Nullable String wifiNetworkKey,
             @Nullable String subscriberId) {
         return new NetworkTemplate(MATCH_WIFI, subscriberId, new String[] { subscriberId },
-                networkId, METERED_ALL, ROAMING_ALL,
-                DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL,
-                SUBSCRIBER_ID_MATCH_RULE_EXACT);
+                wifiNetworkKey != null
+                        ? new String[] { wifiNetworkKey } : new String[0],
+                METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL,
+                NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT);
     }
 
     /**
@@ -327,9 +337,11 @@
     public static NetworkTemplate buildTemplateCarrierMetered(@NonNull String subscriberId) {
         Objects.requireNonNull(subscriberId);
         return new NetworkTemplate(MATCH_CARRIER, subscriberId,
-                new String[] { subscriberId }, null /* networkId */, METERED_YES, ROAMING_ALL,
+                new String[] { subscriberId },
+                new String[0] /* matchWifiNetworkKeys */,
+                METERED_YES, ROAMING_ALL,
                 DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL,
-                SUBSCRIBER_ID_MATCH_RULE_EXACT);
+                NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT);
     }
 
     private final int mMatchRule;
@@ -345,7 +357,8 @@
      */
     private final String[] mMatchSubscriberIds;
 
-    private final String mNetworkId;
+    @NonNull
+    private final String[] mMatchWifiNetworkKeys;
 
     // Matches for the NetworkStats constants METERED_*, ROAMING_* and DEFAULT_NETWORK_*.
     private final int mMetered;
@@ -361,14 +374,14 @@
     // Bitfield containing OEM network properties{@code NetworkIdentity#OEM_*}.
     private final int mOemManaged;
 
-    private void checkValidSubscriberIdMatchRule() {
-        switch (mMatchRule) {
+    private static void checkValidSubscriberIdMatchRule(int matchRule, int subscriberIdMatchRule) {
+        switch (matchRule) {
             case MATCH_MOBILE:
             case MATCH_CARRIER:
                 // MOBILE and CARRIER templates must always specify a subscriber ID.
-                if (mSubscriberIdMatchRule == SUBSCRIBER_ID_MATCH_RULE_ALL) {
-                    throw new IllegalArgumentException("Invalid SubscriberIdMatchRule"
-                            + "on match rule: " + getMatchRuleName(mMatchRule));
+                if (subscriberIdMatchRule == NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_ALL) {
+                    throw new IllegalArgumentException("Invalid SubscriberIdMatchRule "
+                            + "on match rule: " + getMatchRuleName(matchRule));
                 }
                 return;
             default:
@@ -379,49 +392,53 @@
     /** @hide */
     // TODO: Deprecate this constructor, mark it @UnsupportedAppUsage(maxTargetSdk = S)
     @UnsupportedAppUsage
-    public NetworkTemplate(int matchRule, String subscriberId, String networkId) {
-        this(matchRule, subscriberId, new String[] { subscriberId }, networkId);
+    public NetworkTemplate(int matchRule, String subscriberId, String wifiNetworkKey) {
+        this(matchRule, subscriberId, new String[] { subscriberId }, wifiNetworkKey);
     }
 
     /** @hide */
     public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds,
-            String networkId) {
+            String wifiNetworkKey) {
         // Older versions used to only match MATCH_MOBILE and MATCH_MOBILE_WILDCARD templates
         // to metered networks. It is now possible to match mobile with any meteredness, but
         // in order to preserve backward compatibility of @UnsupportedAppUsage methods, this
         //constructor passes METERED_YES for these types.
-        this(matchRule, subscriberId, matchSubscriberIds, networkId,
+        this(matchRule, subscriberId, matchSubscriberIds,
+                wifiNetworkKey != null ? new String[] { wifiNetworkKey } : new String[0],
                 (matchRule == MATCH_MOBILE || matchRule == MATCH_MOBILE_WILDCARD) ? METERED_YES
                 : METERED_ALL , ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL,
-                OEM_MANAGED_ALL, SUBSCRIBER_ID_MATCH_RULE_EXACT);
+                OEM_MANAGED_ALL, NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT);
     }
 
     /** @hide */
     // TODO: Remove it after updating all of the caller.
     public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds,
-            String networkId, int metered, int roaming, int defaultNetwork, int subType,
+            String wifiNetworkKey, int metered, int roaming, int defaultNetwork, int subType,
             int oemManaged) {
-        this(matchRule, subscriberId, matchSubscriberIds, networkId, metered, roaming,
-                defaultNetwork, subType, oemManaged, SUBSCRIBER_ID_MATCH_RULE_EXACT);
+        this(matchRule, subscriberId, matchSubscriberIds,
+                wifiNetworkKey != null ? new String[] { wifiNetworkKey } : new String[0],
+                metered, roaming, defaultNetwork, subType, oemManaged,
+                NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT);
     }
 
     /** @hide */
     public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds,
-            String networkId, int metered, int roaming, int defaultNetwork, int subType,
-            int oemManaged, int subscriberIdMatchRule) {
+            String[] matchWifiNetworkKeys, int metered, int roaming,
+            int defaultNetwork, int subType, int oemManaged, int subscriberIdMatchRule) {
+        Objects.requireNonNull(matchWifiNetworkKeys);
         mMatchRule = matchRule;
         mSubscriberId = subscriberId;
         // TODO: Check whether mMatchSubscriberIds = null or mMatchSubscriberIds = {null} when
         // mSubscriberId is null
         mMatchSubscriberIds = matchSubscriberIds;
-        mNetworkId = networkId;
+        mMatchWifiNetworkKeys = matchWifiNetworkKeys;
         mMetered = metered;
         mRoaming = roaming;
         mDefaultNetwork = defaultNetwork;
         mSubType = subType;
         mOemManaged = oemManaged;
         mSubscriberIdMatchRule = subscriberIdMatchRule;
-        checkValidSubscriberIdMatchRule();
+        checkValidSubscriberIdMatchRule(matchRule, subscriberIdMatchRule);
         if (!isKnownMatchRule(matchRule)) {
             throw new IllegalArgumentException("Unknown network template rule " + matchRule
                     + " will not match any identity.");
@@ -432,7 +449,7 @@
         mMatchRule = in.readInt();
         mSubscriberId = in.readString();
         mMatchSubscriberIds = in.createStringArray();
-        mNetworkId = in.readString();
+        mMatchWifiNetworkKeys = in.createStringArray();
         mMetered = in.readInt();
         mRoaming = in.readInt();
         mDefaultNetwork = in.readInt();
@@ -446,7 +463,7 @@
         dest.writeInt(mMatchRule);
         dest.writeString(mSubscriberId);
         dest.writeStringArray(mMatchSubscriberIds);
-        dest.writeString(mNetworkId);
+        dest.writeStringArray(mMatchWifiNetworkKeys);
         dest.writeInt(mMetered);
         dest.writeInt(mRoaming);
         dest.writeInt(mDefaultNetwork);
@@ -472,9 +489,7 @@
             builder.append(", matchSubscriberIds=").append(
                     Arrays.toString(NetworkIdentityUtils.scrubSubscriberIds(mMatchSubscriberIds)));
         }
-        if (mNetworkId != null) {
-            builder.append(", networkId=").append(mNetworkId);
-        }
+        builder.append(", matchWifiNetworkKeys=").append(Arrays.toString(mMatchWifiNetworkKeys));
         if (mMetered != METERED_ALL) {
             builder.append(", metered=").append(NetworkStats.meteredToString(mMetered));
         }
@@ -498,8 +513,8 @@
 
     @Override
     public int hashCode() {
-        return Objects.hash(mMatchRule, mSubscriberId, mNetworkId, mMetered, mRoaming,
-                mDefaultNetwork, mSubType, mOemManaged, mSubscriberIdMatchRule);
+        return Objects.hash(mMatchRule, mSubscriberId, Arrays.hashCode(mMatchWifiNetworkKeys),
+                mMetered, mRoaming, mDefaultNetwork, mSubType, mOemManaged, mSubscriberIdMatchRule);
     }
 
     @Override
@@ -508,22 +523,22 @@
             final NetworkTemplate other = (NetworkTemplate) obj;
             return mMatchRule == other.mMatchRule
                     && Objects.equals(mSubscriberId, other.mSubscriberId)
-                    && Objects.equals(mNetworkId, other.mNetworkId)
                     && mMetered == other.mMetered
                     && mRoaming == other.mRoaming
                     && mDefaultNetwork == other.mDefaultNetwork
                     && mSubType == other.mSubType
                     && mOemManaged == other.mOemManaged
-                    && mSubscriberIdMatchRule == other.mSubscriberIdMatchRule;
+                    && mSubscriberIdMatchRule == other.mSubscriberIdMatchRule
+                    && Arrays.equals(mMatchWifiNetworkKeys, other.mMatchWifiNetworkKeys);
         }
         return false;
     }
 
-    private String subscriberIdMatchRuleToString(int rule) {
+    private static String subscriberIdMatchRuleToString(int rule) {
         switch (rule) {
-            case SUBSCRIBER_ID_MATCH_RULE_EXACT:
+            case NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT:
                 return "EXACT_MATCH";
-            case SUBSCRIBER_ID_MATCH_RULE_ALL:
+            case NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_ALL:
                 return "ALL";
             default:
                 return "Unknown rule " + rule;
@@ -542,39 +557,25 @@
     }
 
     /**
-     * Check if the template can be persisted into disk.
-     *
-     * @hide
-     */
-    // TODO: Move to the NetworkPolicy.
-    public boolean isPersistable() {
-        switch (mMatchRule) {
-            case MATCH_MOBILE_WILDCARD:
-            case MATCH_WIFI_WILDCARD:
-                return false;
-            case MATCH_CARRIER:
-                return mSubscriberId != null;
-            case MATCH_WIFI:
-                if (Objects.equals(mNetworkId, WIFI_NETWORKID_ALL)
-                        && mSubscriberIdMatchRule == SUBSCRIBER_ID_MATCH_RULE_ALL) {
-                    return false;
-                }
-                return true;
-            default:
-                return true;
-        }
-    }
-
-    /**
      * Get match rule of the template. See {@code MATCH_*}.
      */
     @UnsupportedAppUsage
     public int getMatchRule() {
-        return mMatchRule;
+        // Wildcard rules are not exposed. For external callers, convert wildcard rules to
+        // exposed rules before returning.
+        switch (mMatchRule) {
+            case MATCH_MOBILE_WILDCARD:
+                return MATCH_MOBILE;
+            case MATCH_WIFI_WILDCARD:
+                return MATCH_WIFI;
+            default:
+                return mMatchRule;
+        }
     }
 
     /**
      * Get subscriber Id of the template.
+     * @hide
      */
     @Nullable
     @UnsupportedAppUsage
@@ -582,15 +583,28 @@
         return mSubscriberId;
     }
 
-    public String getNetworkId() {
-        return mNetworkId;
+    /**
+     * Get set of subscriber Ids of the template.
+     */
+    @NonNull
+    public Set<String> getSubscriberIds() {
+        return new ArraySet<>(Arrays.asList(mMatchSubscriberIds));
     }
 
     /**
-     * Get Subscriber Id Match Rule of the template.
+     * Get the set of Wifi Network Keys of the template.
+     * See {@link WifiInfo#getCurrentNetworkKey()}.
      */
-    public int getSubscriberIdMatchRule() {
-        return mSubscriberIdMatchRule;
+    @NonNull
+    public Set<String> getWifiNetworkKeys() {
+        return new ArraySet<>(Arrays.asList(mMatchWifiNetworkKeys));
+    }
+
+    /** @hide */
+    // TODO: Remove this and replace all callers with {@link #getWifiNetworkKeys()}.
+    @Nullable
+    public String getNetworkId() {
+        return getWifiNetworkKeys().isEmpty() ? null : getWifiNetworkKeys().iterator().next();
     }
 
     /**
@@ -602,6 +616,38 @@
     }
 
     /**
+     * Get roaming filter of the template.
+     */
+    @NetworkStats.Roaming
+    public int getRoaming() {
+        return mRoaming;
+    }
+
+    /**
+     * Get the default network status filter of the template.
+     */
+    @NetworkStats.DefaultNetwork
+    public int getDefaultNetworkStatus() {
+        return mDefaultNetwork;
+    }
+
+    /**
+     * Get the Radio Access Technology(RAT) type filter of the template.
+     */
+    public int getRatType() {
+        return mSubType;
+    }
+
+    /**
+     * Get the OEM managed filter of the template. See {@code OEM_MANAGED_*} or
+     * {@code android.net.NetworkIdentity#OEM_*}.
+     */
+    @OemManaged
+    public int getOemManaged() {
+        return mOemManaged;
+    }
+
+    /**
      * Test if given {@link NetworkIdentity} matches this template.
      *
      * @hide
@@ -674,29 +720,34 @@
      * @hide
      */
     public boolean matchesSubscriberId(@Nullable String subscriberId) {
-        return mSubscriberIdMatchRule == SUBSCRIBER_ID_MATCH_RULE_ALL
-                || ArrayUtils.contains(mMatchSubscriberIds, subscriberId);
+        return mSubscriberIdMatchRule == NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_ALL
+                || CollectionUtils.contains(mMatchSubscriberIds, subscriberId);
     }
 
     /**
-     * Check if network with matching SSID. Returns true when the SSID matches, or when
-     * {@code mNetworkId} is {@code WIFI_NETWORKID_ALL}.
+     * Check if network matches key of the wifi network.
+     * Returns true when the key matches, or when {@code mMatchWifiNetworkKeys} is
+     * empty.
+     *
+     * @param wifiNetworkKey key of the wifi network. see {@link WifiInfo#getCurrentNetworkKey()}
+     *                  to know details about the key.
      */
-    private boolean matchesWifiNetworkId(@Nullable String networkId) {
-        return Objects.equals(mNetworkId, WIFI_NETWORKID_ALL)
-                || Objects.equals(sanitizeSsid(mNetworkId), sanitizeSsid(networkId));
+    private boolean matchesWifiNetworkKey(@NonNull String wifiNetworkKey) {
+        Objects.requireNonNull(wifiNetworkKey);
+        return CollectionUtils.isEmpty(mMatchWifiNetworkKeys)
+                || CollectionUtils.contains(mMatchWifiNetworkKeys, wifiNetworkKey);
     }
 
     /**
-     * Check if mobile network with matching IMSI.
+     * Check if mobile network matches IMSI.
      */
     private boolean matchesMobile(NetworkIdentity ident) {
         if (ident.mType == TYPE_WIMAX) {
             // TODO: consider matching against WiMAX subscriber identity
             return true;
         } else {
-            return ident.mType == TYPE_MOBILE && !ArrayUtils.isEmpty(mMatchSubscriberIds)
-                    && ArrayUtils.contains(mMatchSubscriberIds, ident.mSubscriberId)
+            return ident.mType == TYPE_MOBILE && !CollectionUtils.isEmpty(mMatchSubscriberIds)
+                    && CollectionUtils.contains(mMatchSubscriberIds, ident.mSubscriberId)
                     && matchesCollapsedRatType(ident);
         }
     }
@@ -786,7 +837,7 @@
         switch (ident.mType) {
             case TYPE_WIFI:
                 return matchesSubscriberId(ident.mSubscriberId)
-                        && matchesWifiNetworkId(ident.mNetworkId);
+                        && matchesWifiNetworkKey(ident.mNetworkId);
             default:
                 return false;
         }
@@ -807,8 +858,8 @@
      */
     private boolean matchesCarrier(NetworkIdentity ident) {
         return ident.mSubscriberId != null
-                && !ArrayUtils.isEmpty(mMatchSubscriberIds)
-                && ArrayUtils.contains(mMatchSubscriberIds, ident.mSubscriberId);
+                && !CollectionUtils.isEmpty(mMatchSubscriberIds)
+                && CollectionUtils.contains(mMatchSubscriberIds, ident.mSubscriberId);
     }
 
     private boolean matchesMobileWildcard(NetworkIdentity ident) {
@@ -925,11 +976,13 @@
         if (template.mSubscriberId == null) return template;
 
         for (String[] merged : mergedList) {
-            if (ArrayUtils.contains(merged, template.mSubscriberId)) {
+            if (CollectionUtils.contains(merged, template.mSubscriberId)) {
                 // Requested template subscriber is part of the merge group; return
                 // a template that matches all merged subscribers.
+                final String[] matchWifiNetworkKeys = template.mMatchWifiNetworkKeys;
                 return new NetworkTemplate(template.mMatchRule, merged[0], merged,
-                        template.mNetworkId);
+                        CollectionUtils.isEmpty(matchWifiNetworkKeys)
+                                ? null : matchWifiNetworkKeys[0]);
             }
         }
 
@@ -948,4 +1001,206 @@
             return new NetworkTemplate[size];
         }
     };
+
+    /**
+     * Builder class for NetworkTemplate.
+     */
+    public static final class Builder {
+        private final int mMatchRule;
+        // Use a SortedSet to provide a deterministic order when fetching the first one.
+        @NonNull
+        private final SortedSet<String> mMatchSubscriberIds =
+                new TreeSet<>(Comparator.nullsFirst(Comparator.naturalOrder()));
+        @NonNull
+        private final SortedSet<String> mMatchWifiNetworkKeys = new TreeSet<>();
+
+        // Matches for the NetworkStats constants METERED_*, ROAMING_* and DEFAULT_NETWORK_*.
+        private int mMetered;
+        private int mRoaming;
+        private int mDefaultNetwork;
+        private int mRatType;
+
+        // Bitfield containing OEM network properties {@code NetworkIdentity#OEM_*}.
+        private int mOemManaged;
+
+        /**
+         * Creates a new Builder with given match rule to construct NetworkTemplate objects.
+         *
+         * @param matchRule the match rule of the template, see {@code MATCH_*}.
+         */
+        public Builder(@TemplateMatchRule final int matchRule) {
+            assertRequestableMatchRule(matchRule);
+            // Initialize members with default values.
+            mMatchRule = matchRule;
+            mMetered = METERED_ALL;
+            mRoaming = ROAMING_ALL;
+            mDefaultNetwork = DEFAULT_NETWORK_ALL;
+            mRatType = NETWORK_TYPE_ALL;
+            mOemManaged = OEM_MANAGED_ALL;
+        }
+
+        /**
+         * Set the Subscriber Ids. Calling this function with an empty set represents
+         * the intention of matching any Subscriber Ids.
+         *
+         * @param subscriberIds the list of Subscriber Ids.
+         * @return this builder.
+         */
+        @NonNull
+        public Builder setSubscriberIds(@NonNull Set<String> subscriberIds) {
+            Objects.requireNonNull(subscriberIds);
+            mMatchSubscriberIds.clear();
+            mMatchSubscriberIds.addAll(subscriberIds);
+            return this;
+        }
+
+        /**
+         * Set the Wifi Network Keys. Calling this function with an empty set represents
+         * the intention of matching any Wifi Network Key.
+         *
+         * @param wifiNetworkKeys the list of Wifi Network Key,
+         *                        see {@link WifiInfo#getCurrentNetworkKey()}.
+         *                        Or an empty list to match all networks.
+         *                        Note that {@code getCurrentNetworkKey()} might get null key
+         *                        when wifi disconnects. However, the caller should never invoke
+         *                        this function with a null Wifi Network Key since such statistics
+         *                        never exists.
+         * @return this builder.
+         */
+        @NonNull
+        public Builder setWifiNetworkKeys(@NonNull Set<String> wifiNetworkKeys) {
+            Objects.requireNonNull(wifiNetworkKeys);
+            for (String key : wifiNetworkKeys) {
+                if (key == null) {
+                    throw new IllegalArgumentException("Null is not a valid key");
+                }
+            }
+            mMatchWifiNetworkKeys.clear();
+            mMatchWifiNetworkKeys.addAll(wifiNetworkKeys);
+            return this;
+        }
+
+        /**
+         * Set the meteredness filter.
+         *
+         * @param metered the meteredness filter.
+         * @return this builder.
+         */
+        @NonNull
+        public Builder setMeteredness(@NetworkStats.Meteredness int metered) {
+            mMetered = metered;
+            return this;
+        }
+
+        /**
+         * Set the roaming filter.
+         *
+         * @param roaming the roaming filter.
+         * @return this builder.
+         */
+        @NonNull
+        public Builder setRoaming(@NetworkStats.Roaming int roaming) {
+            mRoaming = roaming;
+            return this;
+        }
+
+        /**
+         * Set the default network status filter.
+         *
+         * @param defaultNetwork the default network status filter.
+         * @return this builder.
+         */
+        @NonNull
+        public Builder setDefaultNetworkStatus(@NetworkStats.DefaultNetwork int defaultNetwork) {
+            mDefaultNetwork = defaultNetwork;
+            return this;
+        }
+
+        /**
+         * Set the Radio Access Technology(RAT) type filter.
+         *
+         * @param ratType the Radio Access Technology(RAT) type filter. Use
+         *                {@link #NETWORK_TYPE_ALL} to include all network types when filtering.
+         *                See {@code TelephonyManager.NETWORK_TYPE_*}.
+         * @return this builder.
+         */
+        @NonNull
+        public Builder setRatType(@NetworkType int ratType) {
+            // Input will be validated with the match rule when building the template.
+            mRatType = ratType;
+            return this;
+        }
+
+        /**
+         * Set the OEM managed filter.
+         *
+         * @param oemManaged the match rule to match different type of OEM managed network or
+         *                   unmanaged networks. See {@code OEM_MANAGED_*}.
+         * @return this builder.
+         */
+        @NonNull
+        public Builder setOemManaged(@OemManaged int oemManaged) {
+            mOemManaged = oemManaged;
+            return this;
+        }
+
+        /**
+         * Check whether the match rule is requestable.
+         *
+         * @param matchRule the target match rule to be checked.
+         */
+        private static void assertRequestableMatchRule(final int matchRule) {
+            if (!isKnownMatchRule(matchRule)
+                    || matchRule == MATCH_PROXY
+                    || matchRule == MATCH_MOBILE_WILDCARD
+                    || matchRule == MATCH_WIFI_WILDCARD) {
+                throw new IllegalArgumentException("Invalid match rule: "
+                        + getMatchRuleName(matchRule));
+            }
+        }
+
+        private void assertRequestableParameters() {
+            validateWifiNetworkKeys();
+            // TODO: Check all the input are legitimate.
+        }
+
+        private void validateWifiNetworkKeys() {
+            if (mMatchRule != MATCH_WIFI && !mMatchWifiNetworkKeys.isEmpty()) {
+                throw new IllegalArgumentException("Trying to build non wifi match rule: "
+                        + mMatchRule + " with wifi network keys");
+            }
+        }
+
+        /**
+         * For backward compatibility, deduce match rule to a wildcard match rule
+         * if the Subscriber Ids are empty.
+         */
+        private int getWildcardDeducedMatchRule() {
+            if (mMatchRule == MATCH_MOBILE && mMatchSubscriberIds.isEmpty()) {
+                return MATCH_MOBILE_WILDCARD;
+            } else if (mMatchRule == MATCH_WIFI && mMatchSubscriberIds.isEmpty()
+                    && mMatchWifiNetworkKeys.isEmpty()) {
+                return MATCH_WIFI_WILDCARD;
+            }
+            return mMatchRule;
+        }
+
+        /**
+         * Builds the instance of the NetworkTemplate.
+         *
+         * @return the built instance of NetworkTemplate.
+         */
+        @NonNull
+        public NetworkTemplate build() {
+            assertRequestableParameters();
+            final int subscriberIdMatchRule = mMatchSubscriberIds.isEmpty()
+                    ? NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_ALL
+                    : NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT;
+            return new NetworkTemplate(getWildcardDeducedMatchRule(),
+                    mMatchSubscriberIds.isEmpty() ? null : mMatchSubscriberIds.iterator().next(),
+                    mMatchSubscriberIds.toArray(new String[0]),
+                    mMatchWifiNetworkKeys.toArray(new String[0]), mMetered, mRoaming,
+                    mDefaultNetwork, mRatType, mOemManaged, subscriberIdMatchRule);
+        }
+    }
 }
diff --git a/packages/ConnectivityT/framework-t/src/android/net/TrafficStats.java b/packages/ConnectivityT/framework-t/src/android/net/TrafficStats.java
index fa65061..d8feb88 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/TrafficStats.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/TrafficStats.java
@@ -29,7 +29,6 @@
 import android.os.Build;
 import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.util.DataUnit;
 
 import com.android.server.NetworkManagementSocketTagger;
 
@@ -59,19 +58,19 @@
      */
     public final static int UNSUPPORTED = -1;
 
-    /** @hide @deprecated use {@link DataUnit} instead to clarify SI-vs-IEC */
+    /** @hide @deprecated use {@code DataUnit} instead to clarify SI-vs-IEC */
     @Deprecated
     public static final long KB_IN_BYTES = 1024;
-    /** @hide @deprecated use {@link DataUnit} instead to clarify SI-vs-IEC */
+    /** @hide @deprecated use {@code DataUnit} instead to clarify SI-vs-IEC */
     @Deprecated
     public static final long MB_IN_BYTES = KB_IN_BYTES * 1024;
-    /** @hide @deprecated use {@link DataUnit} instead to clarify SI-vs-IEC */
+    /** @hide @deprecated use {@code DataUnit} instead to clarify SI-vs-IEC */
     @Deprecated
     public static final long GB_IN_BYTES = MB_IN_BYTES * 1024;
-    /** @hide @deprecated use {@link DataUnit} instead to clarify SI-vs-IEC */
+    /** @hide @deprecated use {@code DataUnit} instead to clarify SI-vs-IEC */
     @Deprecated
     public static final long TB_IN_BYTES = GB_IN_BYTES * 1024;
-    /** @hide @deprecated use {@link DataUnit} instead to clarify SI-vs-IEC */
+    /** @hide @deprecated use {@code DataUnit} instead to clarify SI-vs-IEC */
     @Deprecated
     public static final long PB_IN_BYTES = TB_IN_BYTES * 1024;
 
diff --git a/packages/ConnectivityT/service/Android.bp b/packages/ConnectivityT/service/Android.bp
index 97dfb64..b261e16 100644
--- a/packages/ConnectivityT/service/Android.bp
+++ b/packages/ConnectivityT/service/Android.bp
@@ -82,8 +82,18 @@
         ":services.connectivity-ethernet-sources",
         ":services.connectivity-ipsec-sources",
         ":services.connectivity-netstats-sources",
-        ":services.connectivity-nsd-sources",
     ],
     path: "src",
     visibility: ["//frameworks/base/services/core"],
 }
+
+filegroup {
+    name: "services.connectivity-tiramisu-updatable-sources",
+    srcs: [
+        ":services.connectivity-nsd-sources",
+    ],
+    path: "src",
+    visibility: [
+        "//packages/modules/Connectivity:__subpackages__",
+    ],
+}
diff --git a/packages/ConnectivityT/service/src/com/android/server/IpSecService.java b/packages/ConnectivityT/service/src/com/android/server/IpSecService.java
index d1e432e..179d945 100644
--- a/packages/ConnectivityT/service/src/com/android/server/IpSecService.java
+++ b/packages/ConnectivityT/service/src/com/android/server/IpSecService.java
@@ -1236,37 +1236,53 @@
         int callingUid = Binder.getCallingUid();
         UserRecord userRecord = mUserResourceTracker.getUserRecord(callingUid);
         final int resourceId = mNextResourceId++;
-        FileDescriptor sockFd = null;
+
+        ParcelFileDescriptor pFd = null;
         try {
             if (!userRecord.mSocketQuotaTracker.isAvailable()) {
                 return new IpSecUdpEncapResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE);
             }
 
-            sockFd = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
-            mUidFdTagger.tag(sockFd, callingUid);
+            FileDescriptor sockFd = null;
+            try {
+                sockFd = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+                pFd = ParcelFileDescriptor.dup(sockFd);
+            } finally {
+                IoUtils.closeQuietly(sockFd);
+            }
 
+            mUidFdTagger.tag(pFd.getFileDescriptor(), callingUid);
             // This code is common to both the unspecified and specified port cases
             Os.setsockoptInt(
-                    sockFd,
+                    pFd.getFileDescriptor(),
                     OsConstants.IPPROTO_UDP,
                     OsConstants.UDP_ENCAP,
                     OsConstants.UDP_ENCAP_ESPINUDP);
 
-            mNetd.ipSecSetEncapSocketOwner(new ParcelFileDescriptor(sockFd), callingUid);
+            mNetd.ipSecSetEncapSocketOwner(pFd, callingUid);
             if (port != 0) {
                 Log.v(TAG, "Binding to port " + port);
-                Os.bind(sockFd, INADDR_ANY, port);
+                Os.bind(pFd.getFileDescriptor(), INADDR_ANY, port);
             } else {
-                port = bindToRandomPort(sockFd);
+                port = bindToRandomPort(pFd.getFileDescriptor());
             }
 
             userRecord.mEncapSocketRecords.put(
                     resourceId,
                     new RefcountedResource<EncapSocketRecord>(
-                            new EncapSocketRecord(resourceId, sockFd, port), binder));
-            return new IpSecUdpEncapResponse(IpSecManager.Status.OK, resourceId, port, sockFd);
+                            new EncapSocketRecord(resourceId, pFd.getFileDescriptor(), port),
+                            binder));
+            return new IpSecUdpEncapResponse(IpSecManager.Status.OK, resourceId, port,
+                    pFd.getFileDescriptor());
         } catch (IOException | ErrnoException e) {
-            IoUtils.closeQuietly(sockFd);
+            try {
+                if (pFd != null) {
+                    pFd.close();
+                }
+            } catch (IOException ex) {
+                // Nothing can be done at this point
+                Log.e(TAG, "Failed to close pFd.");
+            }
         }
         // If we make it to here, then something has gone wrong and we couldn't open a socket.
         // The only reasonable condition that would cause that is resource unavailable.
diff --git a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsFactory.java b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsFactory.java
index e6433db..bb123a3 100644
--- a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsFactory.java
+++ b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsFactory.java
@@ -24,19 +24,19 @@
 
 import static com.android.server.NetworkManagementSocketTagger.kernelToTag;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.net.INetd;
 import android.net.NetworkStats;
 import android.net.UnderlyingNetworkInfo;
-import android.net.util.NetdService;
 import android.os.RemoteException;
 import android.os.StrictMode;
 import android.os.SystemClock;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.ProcFileReader;
+import com.android.net.module.util.CollectionUtils;
 
 import libcore.io.IoUtils;
 
@@ -70,7 +70,7 @@
 
     private final boolean mUseBpfStats;
 
-    private INetd mNetdService;
+    private final INetd mNetd;
 
     /**
      * Guards persistent data access in this class
@@ -158,12 +158,12 @@
         NetworkStats.apply464xlatAdjustments(baseTraffic, stackedTraffic, mStackedIfaces);
     }
 
-    public NetworkStatsFactory() {
-        this(new File("/proc/"), true);
+    public NetworkStatsFactory(@NonNull INetd netd) {
+        this(new File("/proc/"), true, netd);
     }
 
     @VisibleForTesting
-    public NetworkStatsFactory(File procRoot, boolean useBpfStats) {
+    public NetworkStatsFactory(File procRoot, boolean useBpfStats, @NonNull INetd netd) {
         mStatsXtIfaceAll = new File(procRoot, "net/xt_qtaguid/iface_stat_all");
         mStatsXtIfaceFmt = new File(procRoot, "net/xt_qtaguid/iface_stat_fmt");
         mStatsXtUid = new File(procRoot, "net/xt_qtaguid/stats");
@@ -172,6 +172,7 @@
             mPersistSnapshot = new NetworkStats(SystemClock.elapsedRealtime(), -1);
             mTunAnd464xlatAdjustedStats = new NetworkStats(SystemClock.elapsedRealtime(), -1);
         }
+        mNetd = netd;
     }
 
     public NetworkStats readBpfNetworkStatsDev() throws IOException {
@@ -298,10 +299,7 @@
         // Ask netd to do a active map stats swap. When the binder call successfully returns,
         // the system server should be able to safely read and clean the inactive map
         // without race problem.
-        if (mNetdService == null) {
-            mNetdService = NetdService.getInstance();
-        }
-        mNetdService.trafficSwapActiveStatsMap();
+        mNetd.trafficSwapActiveStatsMap();
     }
 
     /**
@@ -434,7 +432,7 @@
                 entry.txBytes = reader.nextLong();
                 entry.txPackets = reader.nextLong();
 
-                if ((limitIfaces == null || ArrayUtils.contains(limitIfaces, entry.iface))
+                if ((limitIfaces == null || CollectionUtils.contains(limitIfaces, entry.iface))
                         && (limitUid == UID_ALL || limitUid == entry.uid)
                         && (limitTag == TAG_ALL || limitTag == entry.tag)) {
                     stats.insertEntry(entry);
diff --git a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsObservers.java b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsObservers.java
index 1a0866d..b57a4f9 100644
--- a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsObservers.java
+++ b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsObservers.java
@@ -18,8 +18,6 @@
 
 import static android.app.usage.NetworkStatsManager.MIN_THRESHOLD_BYTES;
 
-import static com.android.internal.util.Preconditions.checkArgument;
-
 import android.app.usage.NetworkStatsManager;
 import android.net.DataUsageRequest;
 import android.net.NetworkIdentitySet;
@@ -38,7 +36,7 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.util.ArrayMap;
-import android.util.Slog;
+import android.util.Log;
 import android.util.SparseArray;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -83,7 +81,7 @@
         RequestInfo requestInfo = buildRequestInfo(request, messenger, binder, callingUid,
                 accessLevel);
 
-        if (LOGV) Slog.v(TAG, "Registering observer for " + request);
+        if (LOGV) Log.v(TAG, "Registering observer for " + request);
         getHandler().sendMessage(mHandler.obtainMessage(MSG_REGISTER, requestInfo));
         return request;
     }
@@ -116,7 +114,7 @@
         if (mHandler == null) {
             synchronized (this) {
                 if (mHandler == null) {
-                    if (LOGV) Slog.v(TAG, "Creating handler");
+                    if (LOGV) Log.v(TAG, "Creating handler");
                     mHandler = new Handler(getHandlerLooperLocked(), mHandlerCallback);
                 }
             }
@@ -172,15 +170,15 @@
         RequestInfo requestInfo;
         requestInfo = mDataUsageRequests.get(request.requestId);
         if (requestInfo == null) {
-            if (LOGV) Slog.v(TAG, "Trying to unregister unknown request " + request);
+            if (LOGV) Log.v(TAG, "Trying to unregister unknown request " + request);
             return;
         }
         if (Process.SYSTEM_UID != callingUid && requestInfo.mCallingUid != callingUid) {
-            Slog.w(TAG, "Caller uid " + callingUid + " is not owner of " + request);
+            Log.w(TAG, "Caller uid " + callingUid + " is not owner of " + request);
             return;
         }
 
-        if (LOGV) Slog.v(TAG, "Unregistering " + request);
+        if (LOGV) Log.v(TAG, "Unregistering " + request);
         mDataUsageRequests.remove(request.requestId);
         requestInfo.unlinkDeathRecipient();
         requestInfo.callCallback(NetworkStatsManager.CALLBACK_RELEASED);
@@ -201,7 +199,7 @@
         // Cap the minimum threshold to a safe default to avoid too many callbacks
         long thresholdInBytes = Math.max(MIN_THRESHOLD_BYTES, request.thresholdInBytes);
         if (thresholdInBytes < request.thresholdInBytes) {
-            Slog.w(TAG, "Threshold was too low for " + request
+            Log.w(TAG, "Threshold was too low for " + request
                     + ". Overriding to a safer default of " + thresholdInBytes + " bytes");
         }
         return new DataUsageRequest(mNextDataUsageRequestId.incrementAndGet(),
@@ -216,7 +214,10 @@
                     accessLevel);
         } else {
             // Safety check in case a new access level is added and we forgot to update this
-            checkArgument(accessLevel >= NetworkStatsAccess.Level.DEVICESUMMARY);
+            if (accessLevel < NetworkStatsAccess.Level.DEVICESUMMARY) {
+                throw new IllegalArgumentException(
+                        "accessLevel " + accessLevel + " is less than DEVICESUMMARY.");
+            }
             return new NetworkUsageRequestInfo(this, request, messenger, binder, callingUid,
                     accessLevel);
         }
@@ -255,8 +256,9 @@
 
         @Override
         public void binderDied() {
-            if (LOGV) Slog.v(TAG, "RequestInfo binderDied("
-                    + mRequest + ", " + mBinder + ")");
+            if (LOGV) {
+                Log.v(TAG, "RequestInfo binderDied(" + mRequest + ", " + mBinder + ")");
+            }
             mStatsObserver.unregister(mRequest, Process.SYSTEM_UID);
             callCallback(NetworkStatsManager.CALLBACK_RELEASED);
         }
@@ -299,13 +301,13 @@
             msg.setData(bundle);
             try {
                 if (LOGV) {
-                    Slog.v(TAG, "sending notification " + callbackTypeToName(callbackType)
+                    Log.v(TAG, "sending notification " + callbackTypeToName(callbackType)
                             + " for " + mRequest);
                 }
                 mMessenger.send(msg);
             } catch (RemoteException e) {
                 // May occur naturally in the race of binder death.
-                Slog.w(TAG, "RemoteException caught trying to send a callback msg for " + mRequest);
+                Log.w(TAG, "RemoteException caught trying to send a callback msg for " + mRequest);
             }
         }
 
@@ -341,7 +343,7 @@
         protected boolean checkStats() {
             long bytesSoFar = getTotalBytesForNetwork(mRequest.template);
             if (LOGV) {
-                Slog.v(TAG, bytesSoFar + " bytes so far since notification for "
+                Log.v(TAG, bytesSoFar + " bytes so far since notification for "
                         + mRequest.template);
             }
             if (bytesSoFar > mRequest.thresholdInBytes) {
@@ -416,7 +418,7 @@
                 return history.getTotalBytes();
             } catch (SecurityException e) {
                 if (LOGV) {
-                    Slog.w(TAG, "CallerUid " + mCallingUid + " may have lost access to uid "
+                    Log.w(TAG, "CallerUid " + mCallingUid + " may have lost access to uid "
                             + uid);
                 }
                 return 0;
diff --git a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsRecorder.java b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsRecorder.java
index 5e27c77..c371f08 100644
--- a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsRecorder.java
+++ b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsRecorder.java
@@ -32,15 +32,12 @@
 import android.os.Binder;
 import android.os.DropBoxManager;
 import android.service.NetworkStatsRecorderProto;
+import android.util.IndentingPrintWriter;
 import android.util.Log;
-import android.util.MathUtils;
-import android.util.Slog;
 import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.util.FileRotator;
-import com.android.internal.util.IndentingPrintWriter;
-
-import com.google.android.collect.Sets;
+import com.android.net.module.util.NetworkStatsUtils;
 
 import libcore.io.IoUtils;
 
@@ -132,8 +129,8 @@
     }
 
     public void setPersistThreshold(long thresholdBytes) {
-        if (LOGV) Slog.v(TAG, "setPersistThreshold() with " + thresholdBytes);
-        mPersistThresholdBytes = MathUtils.constrain(
+        if (LOGV) Log.v(TAG, "setPersistThreshold() with " + thresholdBytes);
+        mPersistThresholdBytes = NetworkStatsUtils.constrain(
                 thresholdBytes, 1 * KB_IN_BYTES, 100 * MB_IN_BYTES);
     }
 
@@ -185,7 +182,7 @@
     }
 
     private NetworkStatsCollection loadLocked(long start, long end) {
-        if (LOGD) Slog.d(TAG, "loadLocked() reading from disk for " + mCookie);
+        if (LOGD) Log.d(TAG, "loadLocked() reading from disk for " + mCookie);
         final NetworkStatsCollection res = new NetworkStatsCollection(mBucketDuration);
         try {
             mRotator.readMatching(res, start, end);
@@ -207,7 +204,7 @@
      */
     public void recordSnapshotLocked(NetworkStats snapshot,
             Map<String, NetworkIdentitySet> ifaceIdent, long currentTimeMillis) {
-        final HashSet<String> unknownIfaces = Sets.newHashSet();
+        final HashSet<String> unknownIfaces = new HashSet<>();
 
         // skip recording when snapshot missing
         if (snapshot == null) return;
@@ -272,7 +269,7 @@
         mLastSnapshot = snapshot;
 
         if (LOGV && unknownIfaces.size() > 0) {
-            Slog.w(TAG, "unknown interfaces " + unknownIfaces + ", ignoring those stats");
+            Log.w(TAG, "unknown interfaces " + unknownIfaces + ", ignoring those stats");
         }
     }
 
@@ -296,7 +293,7 @@
     public void forcePersistLocked(long currentTimeMillis) {
         Objects.requireNonNull(mRotator, "missing FileRotator");
         if (mPending.isDirty()) {
-            if (LOGD) Slog.d(TAG, "forcePersistLocked() writing for " + mCookie);
+            if (LOGD) Log.d(TAG, "forcePersistLocked() writing for " + mCookie);
             try {
                 mRotator.rewriteActive(mPendingRewriter, currentTimeMillis);
                 mRotator.maybeRotate(currentTimeMillis);
diff --git a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java
index 2beca73..ced2e22 100644
--- a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java
+++ b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java
@@ -25,7 +25,6 @@
 import static android.content.Intent.EXTRA_UID;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.net.NetworkIdentity.SUBTYPE_COMBINED;
-import static android.net.NetworkStack.checkNetworkStackPermission;
 import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
 import static android.net.NetworkStats.IFACE_ALL;
 import static android.net.NetworkStats.IFACE_VT;
@@ -43,7 +42,6 @@
 import static android.net.NetworkStatsHistory.FIELD_ALL;
 import static android.net.NetworkTemplate.buildTemplateMobileWildcard;
 import static android.net.NetworkTemplate.buildTemplateWifiWildcard;
-import static android.net.TetheringManager.ACTION_TETHER_STATE_CHANGED;
 import static android.net.TrafficStats.KB_IN_BYTES;
 import static android.net.TrafficStats.MB_IN_BYTES;
 import static android.net.TrafficStats.UNSUPPORTED;
@@ -90,6 +88,7 @@
 import android.content.pm.PackageManager;
 import android.database.ContentObserver;
 import android.net.DataUsageRequest;
+import android.net.INetd;
 import android.net.INetworkManagementEventObserver;
 import android.net.INetworkStatsService;
 import android.net.INetworkStatsSession;
@@ -107,13 +106,13 @@
 import android.net.NetworkStatsHistory;
 import android.net.NetworkTemplate;
 import android.net.TelephonyNetworkSpecifier;
+import android.net.TetheringManager;
 import android.net.TrafficStats;
 import android.net.UnderlyingNetworkInfo;
 import android.net.Uri;
 import android.net.netstats.provider.INetworkStatsProvider;
 import android.net.netstats.provider.INetworkStatsProviderCallback;
 import android.net.netstats.provider.NetworkStatsProvider;
-import android.os.BestClock;
 import android.os.Binder;
 import android.os.DropBoxManager;
 import android.os.Environment;
@@ -141,28 +140,30 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.EventLog;
+import android.util.IndentingPrintWriter;
 import android.util.Log;
-import android.util.MathUtils;
-import android.util.Slog;
 import android.util.SparseIntArray;
 import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.DumpUtils;
 import com.android.internal.util.FileRotator;
-import com.android.internal.util.IndentingPrintWriter;
+import com.android.net.module.util.BestClock;
 import com.android.net.module.util.BinderUtils;
+import com.android.net.module.util.CollectionUtils;
+import com.android.net.module.util.NetworkStatsUtils;
+import com.android.net.module.util.PermissionUtils;
 import com.android.server.EventLogTags;
 import com.android.server.LocalServices;
 
 import java.io.File;
 import java.io.FileDescriptor;
+import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.time.Clock;
 import java.time.ZoneOffset;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
@@ -410,10 +411,11 @@
         PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
         PowerManager.WakeLock wakeLock =
                 powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
-
+        final INetd netd = INetd.Stub.asInterface(
+                (IBinder) context.getSystemService(Context.NETD_SERVICE));
         final NetworkStatsService service = new NetworkStatsService(context, networkManager,
                 alarmManager, wakeLock, getDefaultClock(),
-                new DefaultNetworkStatsSettings(context), new NetworkStatsFactory(),
+                new DefaultNetworkStatsSettings(context), new NetworkStatsFactory(netd),
                 new NetworkStatsObservers(), getDefaultSystemDir(), getDefaultBaseDir(),
                 new Dependencies());
         service.registerLocalService();
@@ -529,8 +531,9 @@
         }
 
         // watch for tethering changes
-        final IntentFilter tetherFilter = new IntentFilter(ACTION_TETHER_STATE_CHANGED);
-        mContext.registerReceiver(mTetherReceiver, tetherFilter, null, mHandler);
+        final TetheringManager tetheringManager = mContext.getSystemService(TetheringManager.class);
+        tetheringManager.registerTetheringEventCallback(
+                new HandlerExecutor(mHandler), mTetherListener);
 
         // listen for periodic polling events
         final IntentFilter pollFilter = new IntentFilter(ACTION_NETWORK_STATS_POLL);
@@ -586,7 +589,8 @@
 
     @GuardedBy("mStatsLock")
     private void shutdownLocked() {
-        mContext.unregisterReceiver(mTetherReceiver);
+        final TetheringManager tetheringManager = mContext.getSystemService(TetheringManager.class);
+        tetheringManager.unregisterTetheringEventCallback(mTetherListener);
         mContext.unregisterReceiver(mPollReceiver);
         mContext.unregisterReceiver(mRemovedReceiver);
         mContext.unregisterReceiver(mUserReceiver);
@@ -646,7 +650,7 @@
         try {
             mNetworkManager.setGlobalAlert(mGlobalAlertBytes);
         } catch (IllegalStateException e) {
-            Slog.w(TAG, "problem registering for global alert: " + e);
+            Log.w(TAG, "problem registering for global alert: " + e);
         } catch (RemoteException e) {
             // ignored; service lives in system_server
         }
@@ -655,8 +659,6 @@
 
     @Override
     public INetworkStatsSession openSession() {
-        // NOTE: if callers want to get non-augmented data, they should go
-        // through the public API
         return openSessionInternal(NetworkStatsManager.FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN, null);
     }
 
@@ -766,7 +768,7 @@
                     return stats;
                 } catch (NullPointerException e) {
                     // TODO: Track down and fix the cause of this crash and remove this catch block.
-                    Slog.wtf(TAG, "NullPointerException in getSummaryForAllUid", e);
+                    Log.wtf(TAG, "NullPointerException in getSummaryForAllUid", e);
                     throw e;
                 }
             }
@@ -811,7 +813,7 @@
 
     private @NetworkStatsAccess.Level int checkAccessLevel(String callingPackage) {
         return NetworkStatsAccess.checkAccessLevel(
-                mContext, Binder.getCallingUid(), callingPackage);
+                mContext, Binder.getCallingPid(), Binder.getCallingUid(), callingPackage);
     }
 
     /**
@@ -823,7 +825,7 @@
         SubscriptionPlan plan = null;
         if ((flags & NetworkStatsManager.FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN) != 0
                 && mSettings.getAugmentEnabled()) {
-            if (LOGD) Slog.d(TAG, "Resolving plan for " + template);
+            if (LOGD) Log.d(TAG, "Resolving plan for " + template);
             final long token = Binder.clearCallingIdentity();
             try {
                 plan = LocalServices.getService(NetworkPolicyManagerInternal.class)
@@ -831,7 +833,7 @@
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
-            if (LOGD) Slog.d(TAG, "Resolved to plan " + plan);
+            if (LOGD) Log.d(TAG, "Resolved to plan " + plan);
         }
         return plan;
     }
@@ -876,8 +878,6 @@
     private long getNetworkTotalBytes(NetworkTemplate template, long start, long end) {
         assertSystemReady();
 
-        // NOTE: if callers want to get non-augmented data, they should go
-        // through the public API
         return internalGetSummaryForNetwork(template,
                 NetworkStatsManager.FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN, start, end,
                 NetworkStatsAccess.Level.DEVICE, Binder.getCallingUid()).getTotalBytes();
@@ -936,7 +936,7 @@
     @Override
     public String[] getMobileIfaces() {
         // TODO (b/192758557): Remove debug log.
-        if (ArrayUtils.contains(mMobileIfaces, null)) {
+        if (CollectionUtils.contains(mMobileIfaces, null)) {
             throw new NullPointerException(
                     "null element in mMobileIfaces: " + Arrays.toString(mMobileIfaces));
         }
@@ -985,7 +985,7 @@
             @NonNull NetworkStateSnapshot[] networkStates,
             @Nullable String activeIface,
             @NonNull UnderlyingNetworkInfo[] underlyingNetworkInfos) {
-        checkNetworkStackPermission(mContext);
+        PermissionUtils.enforceNetworkStackPermission(mContext);
 
         final long token = Binder.clearCallingIdentity();
         try {
@@ -1014,9 +1014,10 @@
 
     private void advisePersistThreshold(long thresholdBytes) {
         // clamp threshold into safe range
-        mPersistThreshold = MathUtils.constrain(thresholdBytes, 128 * KB_IN_BYTES, 2 * MB_IN_BYTES);
+        mPersistThreshold = NetworkStatsUtils.constrain(thresholdBytes,
+                128 * KB_IN_BYTES, 2 * MB_IN_BYTES);
         if (LOGV) {
-            Slog.v(TAG, "advisePersistThreshold() given " + thresholdBytes + ", clamped to "
+            Log.v(TAG, "advisePersistThreshold() given " + thresholdBytes + ", clamped to "
                     + mPersistThreshold);
         }
 
@@ -1153,14 +1154,15 @@
     }
 
     /**
-     * Receiver that watches for {@link Tethering} to claim interface pairs.
+     * Listener that watches for {@link TetheringManager} to claim interface pairs.
      */
-    private BroadcastReceiver mTetherReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            performPoll(FLAG_PERSIST_NETWORK);
-        }
-    };
+    private final TetheringManager.TetheringEventCallback mTetherListener =
+            new TetheringManager.TetheringEventCallback() {
+                @Override
+                public void onUpstreamChanged(@Nullable Network network) {
+                    performPoll(FLAG_PERSIST_NETWORK);
+                }
+            };
 
     private BroadcastReceiver mPollReceiver = new BroadcastReceiver() {
         @Override
@@ -1200,13 +1202,13 @@
             // On background handler thread, and USER_REMOVED is protected
             // broadcast.
 
-            final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
-            if (userId == -1) return;
+            final UserHandle userHandle = intent.getParcelableExtra(Intent.EXTRA_USER);
+            if (userHandle == null) return;
 
             synchronized (mStatsLock) {
                 mWakeLock.acquire();
                 try {
-                    removeUserLocked(userId);
+                    removeUserLocked(userHandle);
                 } finally {
                     mWakeLock.release();
                 }
@@ -1231,7 +1233,7 @@
         @Override
         public void limitReached(String limitName, String iface) {
             // only someone like NMS should be calling us
-            NetworkStack.checkNetworkStackPermission(mContext);
+            PermissionUtils.enforceNetworkStackPermission(mContext);
 
             if (LIMIT_GLOBAL_ALERT.equals(limitName)) {
                 // kick off background poll to collect network stats unless there is already
@@ -1279,7 +1281,7 @@
     private void handleNotifyNetworkStatusLocked(@NonNull Network[] defaultNetworks,
             @NonNull NetworkStateSnapshot[] snapshots) {
         if (!mSystemReady) return;
-        if (LOGV) Slog.v(TAG, "handleNotifyNetworkStatusLocked()");
+        if (LOGV) Log.v(TAG, "handleNotifyNetworkStatusLocked()");
 
         // take one last stats snapshot before updating iface mapping. this
         // isn't perfect, since the kernel may already be counting traffic from
@@ -1303,7 +1305,8 @@
             final int displayTransport =
                     getDisplayTransport(snapshot.getNetworkCapabilities().getTransportTypes());
             final boolean isMobile = (NetworkCapabilities.TRANSPORT_CELLULAR == displayTransport);
-            final boolean isDefault = ArrayUtils.contains(mDefaultNetworks, snapshot.getNetwork());
+            final boolean isDefault = CollectionUtils.contains(
+                    mDefaultNetworks, snapshot.getNetwork());
             final int subType = combineSubtypeEnabled ? SUBTYPE_COMBINED
                     : getSubTypeForStateSnapshot(snapshot);
             final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, snapshot,
@@ -1386,7 +1389,7 @@
 
         mMobileIfaces = mobileIfaces.toArray(new String[0]);
         // TODO (b/192758557): Remove debug log.
-        if (ArrayUtils.contains(mMobileIfaces, null)) {
+        if (CollectionUtils.contains(mMobileIfaces, null)) {
             throw new NullPointerException(
                     "null element in mMobileIfaces: " + Arrays.toString(mMobileIfaces));
         }
@@ -1401,7 +1404,7 @@
         if (spec instanceof TelephonyNetworkSpecifier) {
              return ((TelephonyNetworkSpecifier) spec).getSubscriptionId();
         } else {
-            Slog.wtf(TAG, "getSubIdForState invalid NetworkSpecifier");
+            Log.wtf(TAG, "getSubIdForState invalid NetworkSpecifier");
             return INVALID_SUBSCRIPTION_ID;
         }
     }
@@ -1485,7 +1488,7 @@
         try {
             recordSnapshotLocked(currentTime);
         } catch (IllegalStateException e) {
-            Slog.w(TAG, "problem reading network stats: " + e);
+            Log.w(TAG, "problem reading network stats: " + e);
         } catch (RemoteException e) {
             // ignored; service lives in system_server
         }
@@ -1510,7 +1513,7 @@
     @GuardedBy("mStatsLock")
     private void performPollLocked(int flags) {
         if (!mSystemReady) return;
-        if (LOGV) Slog.v(TAG, "performPollLocked(flags=0x" + Integer.toHexString(flags) + ")");
+        if (LOGV) Log.v(TAG, "performPollLocked(flags=0x" + Integer.toHexString(flags) + ")");
         Trace.traceBegin(TRACE_TAG_NETWORK, "performPollLocked");
 
         final boolean persistNetwork = (flags & FLAG_PERSIST_NETWORK) != 0;
@@ -1632,7 +1635,7 @@
      */
     @GuardedBy("mStatsLock")
     private void removeUidsLocked(int... uids) {
-        if (LOGV) Slog.v(TAG, "removeUidsLocked() for UIDs " + Arrays.toString(uids));
+        if (LOGV) Log.v(TAG, "removeUidsLocked() for UIDs " + Arrays.toString(uids));
 
         // Perform one last poll before removing
         performPollLocked(FLAG_PERSIST_ALL);
@@ -1650,20 +1653,20 @@
      * Clean up {@link #mUidRecorder} after user is removed.
      */
     @GuardedBy("mStatsLock")
-    private void removeUserLocked(int userId) {
-        if (LOGV) Slog.v(TAG, "removeUserLocked() for userId=" + userId);
+    private void removeUserLocked(@NonNull UserHandle userHandle) {
+        if (LOGV) Log.v(TAG, "removeUserLocked() for UserHandle=" + userHandle);
 
         // Build list of UIDs that we should clean up
-        int[] uids = new int[0];
+        final ArrayList<Integer> uids = new ArrayList<>();
         final List<ApplicationInfo> apps = mContext.getPackageManager().getInstalledApplications(
                 PackageManager.MATCH_ANY_USER
                 | PackageManager.MATCH_DISABLED_COMPONENTS);
         for (ApplicationInfo app : apps) {
-            final int uid = UserHandle.getUid(userId, app.uid);
-            uids = ArrayUtils.appendInt(uids, uid);
+            final int uid = userHandle.getUid(app.uid);
+            uids.add(uid);
         }
 
-        removeUidsLocked(uids);
+        removeUidsLocked(CollectionUtils.toIntArray(uids));
     }
 
     private class NetworkStatsManagerInternalImpl extends NetworkStatsManagerInternal {
@@ -1706,7 +1709,7 @@
         public void setStatsProviderWarningAndLimitAsync(
                 @NonNull String iface, long warning, long limit) {
             if (LOGV) {
-                Slog.v(TAG, "setStatsProviderWarningAndLimitAsync("
+                Log.v(TAG, "setStatsProviderWarningAndLimitAsync("
                         + iface + "," + warning + "," + limit + ")");
             }
             invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.onSetWarningAndLimit(iface,
@@ -1716,7 +1719,7 @@
 
     @Override
     protected void dump(FileDescriptor fd, PrintWriter rawWriter, String[] args) {
-        if (!DumpUtils.checkDumpPermission(mContext, TAG, rawWriter)) return;
+        if (!PermissionUtils.checkDumpPermission(mContext, TAG, rawWriter)) return;
 
         long duration = DateUtils.DAY_IN_MILLIS;
         final HashSet<String> argSet = new HashSet<String>();
@@ -1777,15 +1780,15 @@
 
             pw.println("Configs:");
             pw.increaseIndent();
-            pw.printPair(NETSTATS_COMBINE_SUBTYPE_ENABLED, mSettings.getCombineSubtypeEnabled());
+            pw.print(NETSTATS_COMBINE_SUBTYPE_ENABLED, mSettings.getCombineSubtypeEnabled());
             pw.println();
             pw.decreaseIndent();
 
             pw.println("Active interfaces:");
             pw.increaseIndent();
             for (int i = 0; i < mActiveIfaces.size(); i++) {
-                pw.printPair("iface", mActiveIfaces.keyAt(i));
-                pw.printPair("ident", mActiveIfaces.valueAt(i));
+                pw.print("iface", mActiveIfaces.keyAt(i));
+                pw.print("ident", mActiveIfaces.valueAt(i));
                 pw.println();
             }
             pw.decreaseIndent();
@@ -1793,8 +1796,8 @@
             pw.println("Active UID interfaces:");
             pw.increaseIndent();
             for (int i = 0; i < mActiveUidIfaces.size(); i++) {
-                pw.printPair("iface", mActiveUidIfaces.keyAt(i));
-                pw.printPair("ident", mActiveUidIfaces.valueAt(i));
+                pw.print("iface", mActiveUidIfaces.keyAt(i));
+                pw.print("ident", mActiveUidIfaces.valueAt(i));
                 pw.println();
             }
             pw.decreaseIndent();
@@ -1867,7 +1870,7 @@
 
     @GuardedBy("mStatsLock")
     private void dumpProtoLocked(FileDescriptor fd) {
-        final ProtoOutputStream proto = new ProtoOutputStream(fd);
+        final ProtoOutputStream proto = new ProtoOutputStream(new FileOutputStream(fd));
 
         // TODO Right now it writes all history.  Should it limit to the "since-boot" log?
 
diff --git a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java
index 5646c75..9bb7bb8 100644
--- a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java
+++ b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java
@@ -33,7 +33,7 @@
 import android.util.Pair;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.CollectionUtils;
+import com.android.net.module.util.CollectionUtils;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -99,18 +99,20 @@
         // prevent binder call to telephony when querying RAT. Keep listener registration with empty
         // IMSI is meaningless since the RAT type changed is ambiguous for multi-SIM if reported
         // with empty IMSI. So filter the subs w/o a valid IMSI to prevent such registration.
-        final List<Pair<Integer, String>> filteredNewSubs =
-                CollectionUtils.mapNotNull(newSubs, subId -> {
-                    final String subscriberId = mTeleManager.getSubscriberId(subId);
-                    return TextUtils.isEmpty(subscriberId) ? null : new Pair(subId, subscriberId);
-                });
+        final List<Pair<Integer, String>> filteredNewSubs = new ArrayList<>();
+        for (final int subId : newSubs) {
+            final String subscriberId =
+                    mTeleManager.createForSubscriptionId(subId).getSubscriberId();
+            if (!TextUtils.isEmpty(subscriberId)) {
+                filteredNewSubs.add(new Pair(subId, subscriberId));
+            }
+        }
 
         for (final Pair<Integer, String> sub : filteredNewSubs) {
             // Fully match listener with subId and IMSI, since in some rare cases, IMSI might be
             // suddenly change regardless of subId, such as switch IMSI feature in modem side.
             // If that happens, register new listener with new IMSI and remove old one later.
-            if (CollectionUtils.find(mRatListeners,
-                    it -> it.equalsKey(sub.first, sub.second)) != null) {
+            if (CollectionUtils.any(mRatListeners, it -> it.equalsKey(sub.first, sub.second))) {
                 continue;
             }
 
@@ -126,8 +128,8 @@
 
         for (final RatTypeListener listener : new ArrayList<>(mRatListeners)) {
             // If there is no subId and IMSI matched the listener, removes it.
-            if (CollectionUtils.find(filteredNewSubs,
-                    it -> listener.equalsKey(it.first, it.second)) == null) {
+            if (!CollectionUtils.any(filteredNewSubs,
+                    it -> listener.equalsKey(it.first, it.second))) {
                 handleRemoveRatTypeListener(listener);
             }
         }
@@ -148,9 +150,10 @@
      * @return collapsed RatType for the given subscriberId
      */
     public int getRatTypeForSubscriberId(@NonNull String subscriberId) {
-        final RatTypeListener match = CollectionUtils.find(mRatListeners,
+        final int index = CollectionUtils.indexOf(mRatListeners,
                 it -> TextUtils.equals(subscriberId, it.mSubscriberId));
-        return match != null ? match.mLastCollapsedRatType : TelephonyManager.NETWORK_TYPE_UNKNOWN;
+        return index != -1 ? mRatListeners.get(index).mLastCollapsedRatType
+                : TelephonyManager.NETWORK_TYPE_UNKNOWN;
     }
 
     /**
diff --git a/packages/InputDevices/res/values-it/strings.xml b/packages/InputDevices/res/values-it/strings.xml
index ed1ec55..a992b86 100644
--- a/packages/InputDevices/res/values-it/strings.xml
+++ b/packages/InputDevices/res/values-it/strings.xml
@@ -4,11 +4,11 @@
     <string name="app_label" msgid="8016145283189546017">"Dispositivi di immissione"</string>
     <string name="keyboard_layouts_label" msgid="6688773268302087545">"Tastiera Android"</string>
     <string name="keyboard_layout_english_uk_label" msgid="6664258463319999632">"Inglese (UK)"</string>
-    <string name="keyboard_layout_english_us_label" msgid="8994890249649106291">"Inglese (USA)"</string>
-    <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"Inglese (USA), stile internazionale"</string>
-    <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"Inglese (USA), stile Colemak"</string>
-    <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"Inglese (USA), stile Dvorak"</string>
-    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Inglese (USA), stile Workman"</string>
+    <string name="keyboard_layout_english_us_label" msgid="8994890249649106291">"Inglese (US)"</string>
+    <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"Inglese (US), stile internazionale"</string>
+    <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"Inglese (US), stile Colemak"</string>
+    <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"Inglese (US), stile Dvorak"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Inglese (US), stile Workman"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"Tedesco"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"Francese"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Francese (Canada)"</string>
diff --git a/packages/InputDevices/res/values-pl/strings.xml b/packages/InputDevices/res/values-pl/strings.xml
index 25a3a90..4d18215 100644
--- a/packages/InputDevices/res/values-pl/strings.xml
+++ b/packages/InputDevices/res/values-pl/strings.xml
@@ -3,51 +3,51 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="8016145283189546017">"Urządzenia wejściowe"</string>
     <string name="keyboard_layouts_label" msgid="6688773268302087545">"Klawiatura Android"</string>
-    <string name="keyboard_layout_english_uk_label" msgid="6664258463319999632">"Angielski (Wielka Brytania)"</string>
-    <string name="keyboard_layout_english_us_label" msgid="8994890249649106291">"Angielski (USA)"</string>
-    <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"Angielski (USA), międzynarodowy"</string>
-    <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"Angielski (USA), Colemak"</string>
-    <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"Angielski (USA), Dvorak"</string>
-    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Angielski (USA), Workman"</string>
-    <string name="keyboard_layout_german_label" msgid="8451565865467909999">"Niemiecki"</string>
-    <string name="keyboard_layout_french_label" msgid="813450119589383723">"Francuski"</string>
-    <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Francuski (Kanada)"</string>
-    <string name="keyboard_layout_russian_label" msgid="8724879775815042968">"Rosyjski"</string>
-    <string name="keyboard_layout_russian_mac_label" msgid="3795866869038264796">"Rosyjski, Mac"</string>
-    <string name="keyboard_layout_spanish_label" msgid="7091555148131908240">"Hiszpański"</string>
-    <string name="keyboard_layout_swiss_french_label" msgid="4659191025396371684">"Francuski (Szwajcaria)"</string>
-    <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Niemiecki (Szwajcaria)"</string>
-    <string name="keyboard_layout_belgian" msgid="2011984572838651558">"Belgijski"</string>
-    <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Bułgarski"</string>
-    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Bułgarski (znaki fonetyczne)"</string>
-    <string name="keyboard_layout_italian" msgid="6497079660449781213">"Włoski"</string>
-    <string name="keyboard_layout_danish" msgid="8036432066627127851">"Duński"</string>
-    <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Norweski"</string>
-    <string name="keyboard_layout_swedish" msgid="732959109088479351">"Szwedzki"</string>
-    <string name="keyboard_layout_finnish" msgid="5585659438924315466">"Fiński"</string>
-    <string name="keyboard_layout_croatian" msgid="4172229471079281138">"Chorwacki"</string>
-    <string name="keyboard_layout_czech" msgid="1349256901452975343">"Czeski"</string>
-    <string name="keyboard_layout_czech_qwerty" msgid="3331402534128515501">"Styl czeskiej klawiatury QWERTY"</string>
-    <string name="keyboard_layout_estonian" msgid="8775830985185665274">"Estoński"</string>
-    <string name="keyboard_layout_hungarian" msgid="4154963661406035109">"Węgierski"</string>
-    <string name="keyboard_layout_icelandic" msgid="5836645650912489642">"Islandzki"</string>
-    <string name="keyboard_layout_brazilian" msgid="5117896443147781939">"Brazylijski"</string>
-    <string name="keyboard_layout_portuguese" msgid="2888198587329660305">"Portugalski"</string>
-    <string name="keyboard_layout_slovak" msgid="2469379934672837296">"Słowacki"</string>
-    <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Słoweński"</string>
-    <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Turecki"</string>
-    <string name="keyboard_layout_turkish_f" msgid="9130320856010776018">"Turecka F"</string>
-    <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ukraiński"</string>
+    <string name="keyboard_layout_english_uk_label" msgid="6664258463319999632">"angielski (Wielka Brytania)"</string>
+    <string name="keyboard_layout_english_us_label" msgid="8994890249649106291">"angielski (USA)"</string>
+    <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"angielski (USA), międzynarodowy"</string>
+    <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"angielski (USA), Colemak"</string>
+    <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"angielski (USA), Dvorak"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"angielski (USA), Workman"</string>
+    <string name="keyboard_layout_german_label" msgid="8451565865467909999">"niemiecki"</string>
+    <string name="keyboard_layout_french_label" msgid="813450119589383723">"francuski"</string>
+    <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"francuski (Kanada)"</string>
+    <string name="keyboard_layout_russian_label" msgid="8724879775815042968">"rosyjski"</string>
+    <string name="keyboard_layout_russian_mac_label" msgid="3795866869038264796">"rosyjski, Mac"</string>
+    <string name="keyboard_layout_spanish_label" msgid="7091555148131908240">"hiszpański"</string>
+    <string name="keyboard_layout_swiss_french_label" msgid="4659191025396371684">"francuski (Szwajcaria)"</string>
+    <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"niemiecki (Szwajcaria)"</string>
+    <string name="keyboard_layout_belgian" msgid="2011984572838651558">"belgijski"</string>
+    <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"bułgarski"</string>
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"bułgarski (znaki fonetyczne)"</string>
+    <string name="keyboard_layout_italian" msgid="6497079660449781213">"włoski"</string>
+    <string name="keyboard_layout_danish" msgid="8036432066627127851">"duński"</string>
+    <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"norweski"</string>
+    <string name="keyboard_layout_swedish" msgid="732959109088479351">"szwedzki"</string>
+    <string name="keyboard_layout_finnish" msgid="5585659438924315466">"fiński"</string>
+    <string name="keyboard_layout_croatian" msgid="4172229471079281138">"chorwacki"</string>
+    <string name="keyboard_layout_czech" msgid="1349256901452975343">"czeski"</string>
+    <string name="keyboard_layout_czech_qwerty" msgid="3331402534128515501">"czeski, QWERTY"</string>
+    <string name="keyboard_layout_estonian" msgid="8775830985185665274">"estoński"</string>
+    <string name="keyboard_layout_hungarian" msgid="4154963661406035109">"węgierski"</string>
+    <string name="keyboard_layout_icelandic" msgid="5836645650912489642">"islandzki"</string>
+    <string name="keyboard_layout_brazilian" msgid="5117896443147781939">"brazylijski"</string>
+    <string name="keyboard_layout_portuguese" msgid="2888198587329660305">"portugalski"</string>
+    <string name="keyboard_layout_slovak" msgid="2469379934672837296">"słowacki"</string>
+    <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"słoweński"</string>
+    <string name="keyboard_layout_turkish" msgid="7736163250907964898">"turecki"</string>
+    <string name="keyboard_layout_turkish_f" msgid="9130320856010776018">"turecki F"</string>
+    <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"ukraiński"</string>
     <string name="keyboard_layout_arabic" msgid="5671970465174968712">"arabski"</string>
     <string name="keyboard_layout_greek" msgid="7289253560162386040">"grecki"</string>
     <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"hebrajski"</string>
     <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"litewski"</string>
     <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"hiszpański (Ameryka Łacińska)"</string>
     <string name="keyboard_layout_latvian" msgid="4405417142306250595">"łotewski"</string>
-    <string name="keyboard_layout_persian" msgid="3920643161015888527">"Perski"</string>
-    <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"Azerski"</string>
-    <string name="keyboard_layout_polish" msgid="1121588624094925325">"Polski"</string>
-    <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"Białoruski"</string>
-    <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"Mongolski"</string>
-    <string name="keyboard_layout_georgian" msgid="4596185456863747454">"Gruziński"</string>
+    <string name="keyboard_layout_persian" msgid="3920643161015888527">"perski"</string>
+    <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"azerski"</string>
+    <string name="keyboard_layout_polish" msgid="1121588624094925325">"polski"</string>
+    <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"białoruski"</string>
+    <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"mongolski"</string>
+    <string name="keyboard_layout_georgian" msgid="4596185456863747454">"gruziński"</string>
 </resources>
diff --git a/packages/PackageInstaller/res/values-af/strings.xml b/packages/PackageInstaller/res/values-af/strings.xml
index 48cf339..a6dcd5d 100644
--- a/packages/PackageInstaller/res/values-af/strings.xml
+++ b/packages/PackageInstaller/res/values-af/strings.xml
@@ -56,6 +56,7 @@
     <string name="uninstall_application_text" msgid="3816830743706143980">"Wil jy hierdie program deïnstalleer?"</string>
     <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Wil jy hierdie program vir "<b>"alle"</b>" gebruikers deïnstalleer? Die program en sy data sal van "<b>"alle"</b>" gebruikers op hierdie toestel verwyder word."</string>
     <string name="uninstall_application_text_user" msgid="498072714173920526">"Wil jy hierdie program vir die gebruiker <xliff:g id="USERNAME">%1$s</xliff:g> deïnstalleer?"</string>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Wil jy hierdie program op jou werkprofiel deïnstalleer?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"Vervang hierdie program met die fabriekweergawe? Alle data sal verwyder word."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Vervang hierdie program met die fabriekweergawe? Alle data sal verwyder word. Dit beïnvloed alle gebruikers van hierdie toestel, insluitend dié met werkprofiele."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"Hou <xliff:g id="SIZE">%1$s</xliff:g> se programdata."</string>
diff --git a/packages/PackageInstaller/res/values-am/strings.xml b/packages/PackageInstaller/res/values-am/strings.xml
index 26d108c..e58923a 100644
--- a/packages/PackageInstaller/res/values-am/strings.xml
+++ b/packages/PackageInstaller/res/values-am/strings.xml
@@ -56,6 +56,7 @@
     <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>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"ይህን መተግበሪያ ከስራ መገለጫዎ ማራገፍ ይፈልጋሉ?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"ይህ መተግበሪያ በፋብሪካው ስሪት ይተካ? ሁሉም ውሂብ ይወገዳል።"</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"ይህ መተግበሪያ በፋብሪካው ስሪት ይተካ? ሁሉም ውሂብ ይወገዳል። እነዚያን የሥራ መገለጫዎች ያላቸውን ጨምሮ ሁሉንም በዚህ መሣሪያ ላይ ባሉ ተጠቃሚዎች ላይ ተጽዕኖ ያሳርፍባቸዋል።"</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"ከመተግበሪያ ውሂብ <xliff:g id="SIZE">%1$s</xliff:g> አቆይ።"</string>
diff --git a/packages/PackageInstaller/res/values-ar/strings.xml b/packages/PackageInstaller/res/values-ar/strings.xml
index af2e19e..2d6fca6 100644
--- a/packages/PackageInstaller/res/values-ar/strings.xml
+++ b/packages/PackageInstaller/res/values-ar/strings.xml
@@ -56,6 +56,7 @@
     <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>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"هل تريد إزالة تثبيت هذا التطبيق من ملفك الشخصي للعمل؟"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"هل تريد استبدال هذا التطبيق بإصدار المصنع؟ ستتم إزالة جميع البيانات."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"هل تريد إعادة ضبط هذا التطبيق على الإعدادات الأصلية؟ سؤدي ذلك إلى إزالة جميع البيانات، كما سيؤثر على جميع مستخدمي هذا الجهاز، بما في ذلك من لديهم ملفات شخصية للعمل."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"الاحتفاظ بالحجم <xliff:g id="SIZE">%1$s</xliff:g> من بيانات التطبيق."</string>
diff --git a/packages/PackageInstaller/res/values-as/strings.xml b/packages/PackageInstaller/res/values-as/strings.xml
index 5224101..bde9394 100644
--- a/packages/PackageInstaller/res/values-as/strings.xml
+++ b/packages/PackageInstaller/res/values-as/strings.xml
@@ -56,6 +56,7 @@
     <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>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"আপুনি নিজৰ কৰ্মস্থানৰ প্ৰ’ফাইলৰ পৰা এই এপ্‌টো আনইনষ্টল কৰিব বিচাৰেনে?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"এই এপ্‌টোৰ ফেক্টৰী সংস্কৰণ ব্যৱহাৰ কৰিব বিচাৰেনে? আটাইবোৰ ডেটা মচা হ\'ব।"</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"এই এপটোৰ ফেক্টৰী সংস্কৰণ ব্যৱহাৰ কৰিব বিচাৰেনে? সকলো ডেটা মচা হ\'ব। কর্মস্থানৰ প্ৰফাইল থকা ব্যৱহাৰকাৰীৰ লগতে ডিভাইচটোৰ সকলো ব্যৱহাৰকাৰীৰ ওপৰত ইয়াৰ প্ৰভাৱ পৰিব।"</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"এপৰ ডেটাৰ <xliff:g id="SIZE">%1$s</xliff:g> ৰাখক"</string>
diff --git a/packages/PackageInstaller/res/values-az/strings.xml b/packages/PackageInstaller/res/values-az/strings.xml
index cbe8783..e4f8541 100644
--- a/packages/PackageInstaller/res/values-az/strings.xml
+++ b/packages/PackageInstaller/res/values-az/strings.xml
@@ -56,6 +56,7 @@
     <string name="uninstall_application_text" msgid="3816830743706143980">"Bu tətbiqi sistemdən silmək istəyirsiniz?"</string>
     <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Bu tətbiqi "<b>"bütün"</b>" istifadəçilər üçün silmək istəyirsiz? Tətbiq və onun datası cihazdakı "<b>"bütün"</b>" istifadəçilər üçün silinəcək."</string>
     <string name="uninstall_application_text_user" msgid="498072714173920526">"<xliff:g id="USERNAME">%1$s</xliff:g> adlı istifadəçi üçün bu tətbiqi sistemdən silmək istəyirsiniz?"</string>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Bu tətbiqi iş profilinizdən silmək istəyirsiniz?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"Tətbiq zavod versiyası ilə əvəz olunsun? Bütün data silinəcək."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Tətbiq zavod versiyası ilə əvəz olunsun? Bütün data silinəcək. Bu, iş profilləri daxil olmaqla bu cihazın bütün istifadəçilərinə təsir edir."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"Tətbiq datasının <xliff:g id="SIZE">%1$s</xliff:g> hissəsini saxlayın."</string>
diff --git a/packages/PackageInstaller/res/values-b+sr+Latn/strings.xml b/packages/PackageInstaller/res/values-b+sr+Latn/strings.xml
index 31c8bac..4ac089d 100644
--- a/packages/PackageInstaller/res/values-b+sr+Latn/strings.xml
+++ b/packages/PackageInstaller/res/values-b+sr+Latn/strings.xml
@@ -56,6 +56,7 @@
     <string name="uninstall_application_text" msgid="3816830743706143980">"Želite li da deinstalirate ovu aplikaciju?"</string>
     <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Da li želite da deinstalirate ovu aplikaciju za "<b>"sve"</b>" korisnike? Aplikacija i podaci uz nje biće uklonjeni za "<b>"sve"</b>" korisnike ovog uređaja."</string>
     <string name="uninstall_application_text_user" msgid="498072714173920526">"Želite li da deinstalirate ovu aplikaciju za korisnika <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Da li želite da deinstalirate ovu aplikaciju sa poslovnog profila?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"Želite li da zamenite ovu aplikaciju fabričkom verzijom? Svi podaci će biti uklonjeni."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Želite li da zamenite ovu aplikaciju fabričkom verzijom? Svi podaci će biti uklonjeni. Ovo utiče na sve korisnike ovog uređaja, uključujući i one sa poslovnim profilima."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"Zadrži <xliff:g id="SIZE">%1$s</xliff:g> podataka aplikacije."</string>
diff --git a/packages/PackageInstaller/res/values-be/strings.xml b/packages/PackageInstaller/res/values-be/strings.xml
index 670fad4..8a3fd9f 100644
--- a/packages/PackageInstaller/res/values-be/strings.xml
+++ b/packages/PackageInstaller/res/values-be/strings.xml
@@ -56,6 +56,7 @@
     <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>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Хочаце выдаліць гэту праграму з працоўнага профілю?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"Замяніць гэту праграму заводскай версіяй? Усе даныя будуць выдалены."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Замяніць гэту праграму заводскай версіяй? Усе даныя будуць выдалены. Гэта паўплывае на ўсіх карыстальнікаў гэтай прылады, уключаючы карыстальнікаў з працоўнымі профілямі."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"Захаваць даныя праграмы (<xliff:g id="SIZE">%1$s</xliff:g>)."</string>
diff --git a/packages/PackageInstaller/res/values-bg/strings.xml b/packages/PackageInstaller/res/values-bg/strings.xml
index 99dfc6d..9bd36e4 100644
--- a/packages/PackageInstaller/res/values-bg/strings.xml
+++ b/packages/PackageInstaller/res/values-bg/strings.xml
@@ -56,6 +56,7 @@
     <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>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Искате ли да деинсталирате това приложение от служебния си потребителски профил?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"Това приложение да се замени ли с фабричната версия? Всички данни ще бъдат премахнати."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Това приложение да се замени ли с фабричната версия? Всички данни ще бъдат премахнати. Промяната ще засегне всеки потребител на устройството, включително тези със служебни потребителски профили."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"Запазване на <xliff:g id="SIZE">%1$s</xliff:g> данни от приложението."</string>
diff --git a/packages/PackageInstaller/res/values-bn/strings.xml b/packages/PackageInstaller/res/values-bn/strings.xml
index 0c0dd69..0edb6d6 100644
--- a/packages/PackageInstaller/res/values-bn/strings.xml
+++ b/packages/PackageInstaller/res/values-bn/strings.xml
@@ -56,6 +56,7 @@
     <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>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"আপনার অফিস প্রোফাইল থেকে এই অ্যাপ আনইনস্টল করতে চান?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"ফ্যাক্টরি ভার্সন দিয়ে এই অ্যাপটিকে বদলাতে চান? সব ডেটা মুছে যাবে।"</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"ফ্যাক্টরি ভার্সন দিয়ে এই অ্যাপটিকে বদলাতে চান? সব ডেটা মুছে যাবে। এই ডিভাইসে কাজের প্রোফাইল আছে এমন ব্যবহারকারী সহ সবাই এর দ্বারা প্রভাবিত হবেন।"</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"অ্যাপ ডেটার মধ্যে <xliff:g id="SIZE">%1$s</xliff:g> রেখে দিন।"</string>
diff --git a/packages/PackageInstaller/res/values-bs/strings.xml b/packages/PackageInstaller/res/values-bs/strings.xml
index dc07c02..8602185 100644
--- a/packages/PackageInstaller/res/values-bs/strings.xml
+++ b/packages/PackageInstaller/res/values-bs/strings.xml
@@ -56,6 +56,7 @@
     <string name="uninstall_application_text" msgid="3816830743706143980">"Želite li deinstalirati ovu aplikaciju?"</string>
     <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Želite li deinstalirati ovu aplikaciju za "<b>" sve "</b>" korisnike? Aplikacija i njeni podaci će biti uklonjeni iz "<b>" svih "</b>" korisničkih računa na uređaju."</string>
     <string name="uninstall_application_text_user" msgid="498072714173920526">"Želite li deinstalirati ovu aplikaciju za korisnika <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Želite li deinstalirati ovu aplikaciju s radnog profila?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"Želite li ovu aplikaciju zamijeniti s fabričkom verzijom? Svi podaci će biti uklonjeni."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Želite li ovu aplikaciju zamijeniti s fabričkom verzijom? Svi podaci će biti uklonjeni. To će uticati na sve korisnike uređaja, uključujući i one s radnim profilima."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"Zadržati <xliff:g id="SIZE">%1$s</xliff:g> podataka aplikacije."</string>
diff --git a/packages/PackageInstaller/res/values-ca/strings.xml b/packages/PackageInstaller/res/values-ca/strings.xml
index 5efee3c..577ae27 100644
--- a/packages/PackageInstaller/res/values-ca/strings.xml
+++ b/packages/PackageInstaller/res/values-ca/strings.xml
@@ -56,6 +56,7 @@
     <string name="uninstall_application_text" msgid="3816830743706143980">"Vols desinstal·lar aquesta aplicació?"</string>
     <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Vols desinstal·lar aquesta aplicació per a "<b>"tots"</b>" els usuaris? L\'aplicació i les seves dades se suprimiran per a "<b>"tots"</b>" els usuaris del dispositiu."</string>
     <string name="uninstall_application_text_user" msgid="498072714173920526">"Vols desinstal·lar aquesta aplicació per a l\'usuari <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Vols desinstal·lar aquesta aplicació del teu perfil de treball?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"Vols substituir aquesta aplicació per la versió de fàbrica? Se suprimiran totes les dades."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Vols substituir aquesta aplicació per la versió de fàbrica? Se suprimiran totes les dades. Això afectarà tots els usuaris d\'aquest dispositiu, inclosos els que tinguin un perfil de treball."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"Conserva <xliff:g id="SIZE">%1$s</xliff:g> de dades de l\'aplicació."</string>
diff --git a/packages/PackageInstaller/res/values-cs/strings.xml b/packages/PackageInstaller/res/values-cs/strings.xml
index 4bf63c9..bd18421 100644
--- a/packages/PackageInstaller/res/values-cs/strings.xml
+++ b/packages/PackageInstaller/res/values-cs/strings.xml
@@ -56,6 +56,7 @@
     <string name="uninstall_application_text" msgid="3816830743706143980">"Chcete tuto aplikaci odinstalovat?"</string>
     <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Chcete tuto aplikaci odinstalovat "<b>"všem"</b>" uživatelům? Aplikace a její údaje budou odstraněny "<b>"všem"</b>" uživatelům tohoto zařízení."</string>
     <string name="uninstall_application_text_user" msgid="498072714173920526">"Chcete tuto aplikaci pro uživatele <xliff:g id="USERNAME">%1$s</xliff:g> odinstalovat?"</string>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Chcete tuto aplikaci odinstalovat ze svého pracovního profilu?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"Chcete tuto aplikaci nahradit tovární verzí? Všechna data budou odstraněna."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Chcete tuto aplikaci nahradit tovární verzí? Všechna data budou odstraněna. Tato akce ovlivní všechny uživatele zařízení, včetně uživatelů s pracovním profilem."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"Ponechat data aplikace o velikosti <xliff:g id="SIZE">%1$s</xliff:g>."</string>
diff --git a/packages/PackageInstaller/res/values-da/strings.xml b/packages/PackageInstaller/res/values-da/strings.xml
index 9b711e4..32355ca 100644
--- a/packages/PackageInstaller/res/values-da/strings.xml
+++ b/packages/PackageInstaller/res/values-da/strings.xml
@@ -56,6 +56,7 @@
     <string name="uninstall_application_text" msgid="3816830743706143980">"Vil du afinstallere denne app?"</string>
     <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Vil du afinstallere denne app for "<b>"alle"</b>" brugere? Appen og dens data fjernes fra "<b>"alle"</b>" brugere på denne enhed."</string>
     <string name="uninstall_application_text_user" msgid="498072714173920526">"Vil du afinstallere denne app for brugeren <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Vil du afinstallere denne app fra din arbejdsprofil?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"Vil du erstatte denne app med fabriksversionen? Alle data fjernes."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Vil du erstatte denne app med fabriksversionen? Alle data fjernes. Dette påvirker alle brugere af denne enhed, bl.a. brugere med arbejdsprofiler."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"Behold <xliff:g id="SIZE">%1$s</xliff:g> appdata."</string>
diff --git a/packages/PackageInstaller/res/values-de/strings.xml b/packages/PackageInstaller/res/values-de/strings.xml
index a782fd2..6dc81d0 100644
--- a/packages/PackageInstaller/res/values-de/strings.xml
+++ b/packages/PackageInstaller/res/values-de/strings.xml
@@ -56,6 +56,7 @@
     <string name="uninstall_application_text" msgid="3816830743706143980">"Möchtest du diese App deinstallieren?"</string>
     <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Möchtest du diese App für "<b>"alle"</b>" Nutzer entfernen? Die App und alle zugehörigen Daten werden für "<b>"alle"</b>" Nutzer des Geräts entfernt."</string>
     <string name="uninstall_application_text_user" msgid="498072714173920526">"Möchtest du diese App für den Nutzer <xliff:g id="USERNAME">%1$s</xliff:g> deinstallieren?"</string>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Möchtest du diese App aus deinem Arbeitsprofil deinstallieren?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"Diese App durch die Werksversion ersetzen? Alle Daten werden entfernt."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Diese App durch die Werksversion ersetzen? Alle Daten werden entfernt. Dies betrifft alle Nutzer des Geräts, einschließlich Arbeitsprofilen."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"<xliff:g id="SIZE">%1$s</xliff:g> an App-Daten behalten."</string>
diff --git a/packages/PackageInstaller/res/values-el/strings.xml b/packages/PackageInstaller/res/values-el/strings.xml
index 3fd87d9..c67f6f7 100644
--- a/packages/PackageInstaller/res/values-el/strings.xml
+++ b/packages/PackageInstaller/res/values-el/strings.xml
@@ -56,6 +56,7 @@
     <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>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Θέλετε να καταργήσετε την εγκατάσταση αυτής της εφαρμογής από το προφίλ εργασίας σας;"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"Να αντικατασταθεί αυτή η εφαρμογή με την εργοστασιακή έκδοση; Όλα τα δεδομένα θα καταργηθούν."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Να αντικατασταθεί αυτή η εφαρμογή με την εργοστασιακή έκδοση; Όλα τα δεδομένα θα καταργηθούν. Αυτό επηρεάζει όλους τους χρήστες της συσκευής, συμπεριλαμβανομένων και των κατόχων προφίλ εργασίας."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"Διατήρηση <xliff:g id="SIZE">%1$s</xliff:g> δεδομένων εφαρμογών."</string>
diff --git a/packages/PackageInstaller/res/values-en-rAU/strings.xml b/packages/PackageInstaller/res/values-en-rAU/strings.xml
index a91c882..f09f7bb 100644
--- a/packages/PackageInstaller/res/values-en-rAU/strings.xml
+++ b/packages/PackageInstaller/res/values-en-rAU/strings.xml
@@ -56,6 +56,7 @@
     <string name="uninstall_application_text" msgid="3816830743706143980">"Do you want to uninstall this app?"</string>
     <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Do you want to uninstall this app for "<b>"all"</b>" users? The application and its data will be removed from "<b>"all"</b>" users on the device."</string>
     <string name="uninstall_application_text_user" msgid="498072714173920526">"Do you want to uninstall this app for the user <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Do you want to uninstall this app from your work profile?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"Replace this app with the factory version? All data will be removed."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Replace this app with the factory version? All data will be removed. This affects all users of this device, including those with work profiles."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"Keep <xliff:g id="SIZE">%1$s</xliff:g> of app data."</string>
diff --git a/packages/PackageInstaller/res/values-en-rCA/strings.xml b/packages/PackageInstaller/res/values-en-rCA/strings.xml
index a91c882..f09f7bb 100644
--- a/packages/PackageInstaller/res/values-en-rCA/strings.xml
+++ b/packages/PackageInstaller/res/values-en-rCA/strings.xml
@@ -56,6 +56,7 @@
     <string name="uninstall_application_text" msgid="3816830743706143980">"Do you want to uninstall this app?"</string>
     <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Do you want to uninstall this app for "<b>"all"</b>" users? The application and its data will be removed from "<b>"all"</b>" users on the device."</string>
     <string name="uninstall_application_text_user" msgid="498072714173920526">"Do you want to uninstall this app for the user <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Do you want to uninstall this app from your work profile?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"Replace this app with the factory version? All data will be removed."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Replace this app with the factory version? All data will be removed. This affects all users of this device, including those with work profiles."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"Keep <xliff:g id="SIZE">%1$s</xliff:g> of app data."</string>
diff --git a/packages/PackageInstaller/res/values-en-rGB/strings.xml b/packages/PackageInstaller/res/values-en-rGB/strings.xml
index a91c882..f09f7bb 100644
--- a/packages/PackageInstaller/res/values-en-rGB/strings.xml
+++ b/packages/PackageInstaller/res/values-en-rGB/strings.xml
@@ -56,6 +56,7 @@
     <string name="uninstall_application_text" msgid="3816830743706143980">"Do you want to uninstall this app?"</string>
     <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Do you want to uninstall this app for "<b>"all"</b>" users? The application and its data will be removed from "<b>"all"</b>" users on the device."</string>
     <string name="uninstall_application_text_user" msgid="498072714173920526">"Do you want to uninstall this app for the user <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Do you want to uninstall this app from your work profile?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"Replace this app with the factory version? All data will be removed."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Replace this app with the factory version? All data will be removed. This affects all users of this device, including those with work profiles."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"Keep <xliff:g id="SIZE">%1$s</xliff:g> of app data."</string>
diff --git a/packages/PackageInstaller/res/values-en-rIN/strings.xml b/packages/PackageInstaller/res/values-en-rIN/strings.xml
index a91c882..f09f7bb 100644
--- a/packages/PackageInstaller/res/values-en-rIN/strings.xml
+++ b/packages/PackageInstaller/res/values-en-rIN/strings.xml
@@ -56,6 +56,7 @@
     <string name="uninstall_application_text" msgid="3816830743706143980">"Do you want to uninstall this app?"</string>
     <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Do you want to uninstall this app for "<b>"all"</b>" users? The application and its data will be removed from "<b>"all"</b>" users on the device."</string>
     <string name="uninstall_application_text_user" msgid="498072714173920526">"Do you want to uninstall this app for the user <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Do you want to uninstall this app from your work profile?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"Replace this app with the factory version? All data will be removed."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Replace this app with the factory version? All data will be removed. This affects all users of this device, including those with work profiles."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"Keep <xliff:g id="SIZE">%1$s</xliff:g> of app data."</string>
diff --git a/packages/PackageInstaller/res/values-en-rXC/strings.xml b/packages/PackageInstaller/res/values-en-rXC/strings.xml
index 6a7bddc..fddc164 100644
--- a/packages/PackageInstaller/res/values-en-rXC/strings.xml
+++ b/packages/PackageInstaller/res/values-en-rXC/strings.xml
@@ -56,6 +56,7 @@
     <string name="uninstall_application_text" msgid="3816830743706143980">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‎‏‏‏‏‏‎‎‎‎‎‎‏‏‎‏‏‎‏‎‏‎‏‏‎‏‏‎‎‎‏‏‎‎‏‏‎‎‏‎‏‎‎‎‎‏‏‎‎‏‏‏‎‏‏‎‎‎Do you want to uninstall this app?‎‏‎‎‏‎"</string>
     <string name="uninstall_application_text_all_users" msgid="575491774380227119">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‎‎‏‏‏‎‏‎‏‏‏‎‎‎‎‎‏‏‏‏‏‏‎‎‎‏‎‏‏‏‏‎‏‏‏‎‏‎‎‎‏‎‏‏‏‏‎Do you want to uninstall this app for ‎‏‎‎‏‏‎"<b>"‎‏‎‎‏‏‏‎all‎‏‎‎‏‏‎"</b>"‎‏‎‎‏‏‏‎ users? The application and its data will be removed from ‎‏‎‎‏‏‎"<b>"‎‏‎‎‏‏‏‎all‎‏‎‎‏‏‎"</b>"‎‏‎‎‏‏‏‎ users on the device.‎‏‎‎‏‎"</string>
     <string name="uninstall_application_text_user" msgid="498072714173920526">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‎‏‏‏‎‏‎‎‏‏‎‎‎‎‎‏‎‎‏‏‏‏‏‏‎‏‎‏‎‎‎‎‎‏‎‏‎‎‏‏‎‏‎‏‏‎‏‎‏‎‎‎‎‏‏‏‎‎Do you want to uninstall this app for the user ‎‏‎‎‏‏‎<xliff:g id="USERNAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎?‎‏‎‎‏‎"</string>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‏‏‎‏‏‎‏‎‏‎‎‎‎‎‎‎‎‏‎‏‎‏‏‏‏‏‎‏‎‎‏‏‎‏‎‎‏‏‏‎‎‏‎‏‎‏‏‏‏‏‎‎‎‏‎Do you want to uninstall this app from your work profile?‎‏‎‎‏‎"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‏‏‏‏‏‏‏‎‎‎‏‎‎‏‎‏‏‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‎‏‎‎‎‏‎‎‎‎‎‏‎‏‎‏‎‏‏‎‎‎‎‎‏‎Replace this app with the factory version? All data will be removed.‎‏‎‎‏‎"</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‎‎‏‏‎‏‎‎‏‎‎‎‏‏‏‎‎‏‎‏‎‎‎‏‏‎‏‏‎‏‏‏‎‎‏‏‎‏‎‏‏‎‎‎‏‎‏‏‎‎‏‎‏‏‎Replace this app with the factory version? All data will be removed. This affects all users of this device, including those with work profiles.‎‏‎‎‏‎"</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‎‏‎‎‏‎‏‏‎‏‎‏‏‏‎‎‏‏‎‎‏‎‎‎‏‎‎‏‏‏‎‏‎‏‎‏‎‏‎‎‏‏‏‎‏‎‎‏‎‎‏‎‏‏‏‏‏‎‎Keep ‎‏‎‎‏‏‎<xliff:g id="SIZE">%1$s</xliff:g>‎‏‎‎‏‏‏‎ of app data.‎‏‎‎‏‎"</string>
diff --git a/packages/PackageInstaller/res/values-es-rUS/strings.xml b/packages/PackageInstaller/res/values-es-rUS/strings.xml
index bdacb64..6641e11 100644
--- a/packages/PackageInstaller/res/values-es-rUS/strings.xml
+++ b/packages/PackageInstaller/res/values-es-rUS/strings.xml
@@ -56,6 +56,7 @@
     <string name="uninstall_application_text" msgid="3816830743706143980">"¿Quieres desinstalar esta app?"</string>
     <string name="uninstall_application_text_all_users" msgid="575491774380227119">"¿Quieres desinstalar esta app para "<b>"todos"</b>" los usuarios? Se quitarán la aplicación y sus datos de "<b>"todos"</b>" los usuarios del dispositivo."</string>
     <string name="uninstall_application_text_user" msgid="498072714173920526">"¿Quieres desinstalar esta app para el usuario <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"¿Deseas desinstalar esta app de tu perfil de trabajo?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"¿Deseas reemplazar esta app con la versión de fábrica? Se quitarán todos los datos."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"¿Deseas reemplazar esta app con la versión de fábrica? Se quitarán todos los datos. Esta acción afectará a todos los usuarios de este dispositivo, incluidos los que tengan perfiles de trabajo."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"Guardar <xliff:g id="SIZE">%1$s</xliff:g> en datos de apps"</string>
diff --git a/packages/PackageInstaller/res/values-es/strings.xml b/packages/PackageInstaller/res/values-es/strings.xml
index 7431241..1b000c2 100644
--- a/packages/PackageInstaller/res/values-es/strings.xml
+++ b/packages/PackageInstaller/res/values-es/strings.xml
@@ -56,6 +56,7 @@
     <string name="uninstall_application_text" msgid="3816830743706143980">"¿Quieres desinstalar esta aplicación?"</string>
     <string name="uninstall_application_text_all_users" msgid="575491774380227119">"¿Quieres desinstalar esta aplicación para "<b>"todos"</b>" los usuarios? La aplicación y sus datos se borrarán de "<b>"todos"</b>" los usuarios del dispositivo."</string>
     <string name="uninstall_application_text_user" msgid="498072714173920526">"¿Quieres desinstalar esta aplicación para el usuario <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"¿Quieres desinstalar esta aplicación de tu perfil de trabajo?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"¿Quieres reemplazar esta aplicación con la versión de fábrica? Ten en cuenta que se borrarán todos los datos."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"¿Quieres reemplazar esta aplicación con la versión de fábrica? Ten en cuenta que se borrarán todos los datos. Esto afecta a todos los usuarios del dispositivo, incluidos los que tienen perfiles de trabajo."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"Mantener <xliff:g id="SIZE">%1$s</xliff:g> de datos de aplicaciones."</string>
diff --git a/packages/PackageInstaller/res/values-et/strings.xml b/packages/PackageInstaller/res/values-et/strings.xml
index 2225d3b..0138219 100644
--- a/packages/PackageInstaller/res/values-et/strings.xml
+++ b/packages/PackageInstaller/res/values-et/strings.xml
@@ -56,6 +56,7 @@
     <string name="uninstall_application_text" msgid="3816830743706143980">"Kas soovite selle rakenduse desinstallida?"</string>
     <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Kas soovite selle rakenduse "<b>"kõikide"</b>" kasutajate kontodelt desinstallida? Rakendus ja selle andmed eemaldatakse "<b>"kõikide"</b>" seadme kasutajate kontodelt."</string>
     <string name="uninstall_application_text_user" msgid="498072714173920526">"Kas soovite selle rakenduse kasutaja <xliff:g id="USERNAME">%1$s</xliff:g> kontolt desinstallida?"</string>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Kas soovite selle rakenduse oma tööprofiililt desinstallida?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"Kas asendada see rakendus tehaseversiooniga? Kõik andmed eemaldatakse."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Kas asendada see rakendus tehaseversiooniga? Kõik andmed eemaldatakse. See mõjutab kõiki seadme kasutajaid, sh neid, kellel on tööprofiilid."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"Säilita rakenduse andmete hulk <xliff:g id="SIZE">%1$s</xliff:g>."</string>
diff --git a/packages/PackageInstaller/res/values-eu/strings.xml b/packages/PackageInstaller/res/values-eu/strings.xml
index f5ad2be..aa21b4f 100644
--- a/packages/PackageInstaller/res/values-eu/strings.xml
+++ b/packages/PackageInstaller/res/values-eu/strings.xml
@@ -56,6 +56,7 @@
     <string name="uninstall_application_text" msgid="3816830743706143980">"Aplikazioa desinstalatu nahi duzu?"</string>
     <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Erabiltzaile "<b>"guztiei"</b>" desinstalatu nahi diezu aplikazioa? Aplikazioa eta haren datu guztiak ezabatuko zaizkie gailuko erabiltzaile "<b>"guztiei"</b>"."</string>
     <string name="uninstall_application_text_user" msgid="498072714173920526">"<xliff:g id="USERNAME">%1$s</xliff:g> erabiltzaileari desinstalatu nahi diozu aplikazioa?"</string>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Aplikazioa laneko profiletik desinstalatu nahi duzu?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"Aplikazio hau jatorrizko bertsioarekin ordeztu nahi duzu? Datu guztiak ezabatuko dira."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Aplikazio hau jatorrizko bertsioarekin ordeztu nahi duzu? Datu guztiak ezabatuko dira. Gailuaren erabiltzaile guztiengan izango du eragina, laneko profilak dituztenak barne."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"Mantendu aplikazioetako datuen <xliff:g id="SIZE">%1$s</xliff:g>."</string>
diff --git a/packages/PackageInstaller/res/values-fa/strings.xml b/packages/PackageInstaller/res/values-fa/strings.xml
index 0ec6acf..b05a087 100644
--- a/packages/PackageInstaller/res/values-fa/strings.xml
+++ b/packages/PackageInstaller/res/values-fa/strings.xml
@@ -56,6 +56,7 @@
     <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>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"می‌خواهید این برنامه را از نمایه کاری‌تان حذف نصب کنید؟"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"این برنامه با نسخه کارخانه جایگزین شود؟ همه داده‌ها پاک می‌شود."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"این برنامه با نسخه کارخانه جایگزین شود؟ همه داده‌ها پاک می‌شود. این کار همه کاربران این دستگاه (ازجمله کاربرانی که نمایه کاری دارند) را تحت تأثیر قرار خواهد داد."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"<xliff:g id="SIZE">%1$s</xliff:g> از داده‌های برنامه را نگه‌دارید."</string>
diff --git a/packages/PackageInstaller/res/values-fi/strings.xml b/packages/PackageInstaller/res/values-fi/strings.xml
index 8a52d21..a8048e2 100644
--- a/packages/PackageInstaller/res/values-fi/strings.xml
+++ b/packages/PackageInstaller/res/values-fi/strings.xml
@@ -56,6 +56,7 @@
     <string name="uninstall_application_text" msgid="3816830743706143980">"Haluatko poistaa tämän sovelluksen?"</string>
     <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Haluatko poistaa tämän sovelluksen "<b>"kaikilta"</b>" käyttäjiltä? Sovellus ja sen data poistetaan "<b>"kaikilta"</b>" laitteen käyttäjiltä."</string>
     <string name="uninstall_application_text_user" msgid="498072714173920526">"Haluatko poistaa tämän sovelluksen käyttäjältä <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Haluatko poistaa sovelluksen työprofiilistasi?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"Haluatko korvata tämän sovelluksen tehdasversiolla? Kaikki data poistetaan."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Haluatko korvata tämän sovelluksen tehdasversiolla? Kaikki data poistetaan. Tämä vaikuttaa kaikkiin laitteen käyttäjiin, myös työprofiileihin."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"Säilytä <xliff:g id="SIZE">%1$s</xliff:g> sovellusdataa"</string>
diff --git a/packages/PackageInstaller/res/values-fr-rCA/strings.xml b/packages/PackageInstaller/res/values-fr-rCA/strings.xml
index 4f2a37e..d11336f 100644
--- a/packages/PackageInstaller/res/values-fr-rCA/strings.xml
+++ b/packages/PackageInstaller/res/values-fr-rCA/strings.xml
@@ -56,6 +56,7 @@
     <string name="uninstall_application_text" msgid="3816830743706143980">"Voulez-vous désinstaller cette application?"</string>
     <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Voulez-vous désinstaller cette application pour "<b>"tous"</b>" les utilisateurs? L\'application et ses données seront supprimées pour "<b>"tous"</b>" les utilisateurs de l\'appareil."</string>
     <string name="uninstall_application_text_user" msgid="498072714173920526">"Voulez-vous désinstaller cette application pour l\'utilisateur <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Voulez-vous désinstaller cette application de votre profil professionnel?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"Remplacer cette application par la version d\'usine? Toutes les données seront supprimées."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Remplacer cette application par la version d\'usine? Toutes les données seront supprimées. Cela touchera tous les utilisateurs de cet appareil, y compris ceux qui utilisent un profil professionnel."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"Garder <xliff:g id="SIZE">%1$s</xliff:g> de données d\'application."</string>
diff --git a/packages/PackageInstaller/res/values-fr/strings.xml b/packages/PackageInstaller/res/values-fr/strings.xml
index 3a04a8f..50ca29d 100644
--- a/packages/PackageInstaller/res/values-fr/strings.xml
+++ b/packages/PackageInstaller/res/values-fr/strings.xml
@@ -56,6 +56,7 @@
     <string name="uninstall_application_text" msgid="3816830743706143980">"Voulez-vous désinstaller cette application ?"</string>
     <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Voulez-vous désinstaller cette application pour "<b>"tous"</b>" les utilisateurs ? L\'application et ses données seront supprimées pour "<b>"tous"</b>" les utilisateurs de l\'appareil."</string>
     <string name="uninstall_application_text_user" msgid="498072714173920526">"Voulez-vous désinstaller cette application pour l\'utilisateur <xliff:g id="USERNAME">%1$s</xliff:g> ?"</string>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Voulez-vous désinstaller cette appli de votre profil professionnel ?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"Remplacer cette application par la version d\'usine ? Toutes les données seront supprimées."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Remplacer cette application par la version d\'usine ? Toutes les données seront supprimées. Tous les utilisateurs de cet appareil seront affectés, y compris ceux qui ont un profil professionnel."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"Conserver <xliff:g id="SIZE">%1$s</xliff:g> de données d\'application."</string>
diff --git a/packages/PackageInstaller/res/values-gl/strings.xml b/packages/PackageInstaller/res/values-gl/strings.xml
index ac1f6ac..720a3cb 100644
--- a/packages/PackageInstaller/res/values-gl/strings.xml
+++ b/packages/PackageInstaller/res/values-gl/strings.xml
@@ -56,6 +56,7 @@
     <string name="uninstall_application_text" msgid="3816830743706143980">"Queres desinstalar esta aplicación?"</string>
     <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Queres desinstalar esta aplicación para "<b>"todos"</b>" os usuarios? A aplicación e os seus datos quitaranse de "<b>"todos"</b>" os usuarios do dispositivo."</string>
     <string name="uninstall_application_text_user" msgid="498072714173920526">"Queres desinstalar esta aplicación para o usuario que se chama <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Queres desinstalar esta aplicación do perfil de traballo?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"Queres substituír esta aplicación pola versión que viña de fábrica? Quitaranse todos os datos."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Queres substituír esta aplicación pola versión que viña de fábrica? Quitaranse todos os datos. Isto afectará a todos os usuarios do dispositivo, incluídos os que teñan perfís de traballo."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"Conservar os datos da aplicación, que ocupan <xliff:g id="SIZE">%1$s</xliff:g>."</string>
diff --git a/packages/PackageInstaller/res/values-gu/strings.xml b/packages/PackageInstaller/res/values-gu/strings.xml
index 4c7d02d..4dc7f0b 100644
--- a/packages/PackageInstaller/res/values-gu/strings.xml
+++ b/packages/PackageInstaller/res/values-gu/strings.xml
@@ -56,6 +56,7 @@
     <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>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"શું તમે તમારી ઑફિસની પ્રોફાઇલમાંથી આ ઍપને અનઇન્સ્ટૉલ કરવા માગો છો?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"આ ઍપ્લિકેશનને ફેક્ટરી વર્ઝનથી બદલીએ? બધો ડેટા કાઢી નાખવામાં આવશે."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"આ ઍપ્લિકેશનને ફેક્ટરી વર્ઝનથી બદલીએ? બધો ડેટા કાઢી નાખવામાં આવશે. આનાથી કાર્યાલયની પ્રોફાઇલ ધરાવનારા વપરાશકર્તાઓ સહિત આ ડિવાઇસના બધા વપરાશકર્તાઓ પ્રભાવિત થશે."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"<xliff:g id="SIZE">%1$s</xliff:g>નો ઍપ ડેટા રાખો."</string>
diff --git a/packages/PackageInstaller/res/values-hi/strings.xml b/packages/PackageInstaller/res/values-hi/strings.xml
index 5d59c87..382278e 100644
--- a/packages/PackageInstaller/res/values-hi/strings.xml
+++ b/packages/PackageInstaller/res/values-hi/strings.xml
@@ -56,6 +56,7 @@
     <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>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"क्या अपनी वर्क प्रोफ़ाइल से इस ऐप्लिकेशन को अनइंस्टॉल करना है?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"इस ऐप्लिकेशन को फ़ैक्ट्री वर्शन से बदलें? सभी डेटा हटा दिया जाएगा."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"इस ऐप्लिकेशन को फ़ैक्ट्री वर्शन से बदलें? पूरा डेटा हटा दिया जाएगा. इसका असर इस डिवाइस के सभी उपयोगकर्ताओं पर पड़ेगा, जिनमें काम की प्रोफ़ाइलों वाले उपयोगकर्ता शामिल हैं."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"<xliff:g id="SIZE">%1$s</xliff:g> ऐप्लिकेशन डेटा रखें."</string>
diff --git a/packages/PackageInstaller/res/values-hr/strings.xml b/packages/PackageInstaller/res/values-hr/strings.xml
index a11cc27..707eb4e 100644
--- a/packages/PackageInstaller/res/values-hr/strings.xml
+++ b/packages/PackageInstaller/res/values-hr/strings.xml
@@ -56,6 +56,7 @@
     <string name="uninstall_application_text" msgid="3816830743706143980">"Želite li deinstalirati ovu aplikaciju?"</string>
     <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Želite li deinstalirati tu aplikaciju za "<b>"sve"</b>" korisnike? Aplikacija i njezini podaci bit će uklonjeni sa "<b>"svih"</b>" korisnika na uređaju."</string>
     <string name="uninstall_application_text_user" msgid="498072714173920526">"Želite li deinstalirati tu aplikaciju za korisnika <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Želite li deinstalirati tu aplikaciju s poslovnog profila?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"Želite li tu aplikaciju zamijeniti tvorničkom verzijom? Izgubit ćete sve podatke."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Želite li tu aplikaciju zamijeniti tvorničkom verzijom? Izgubit ćete sve podatke. To se odnosi na sve korisnike uređaja, uključujući one s radnim profilima."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"Zadrži <xliff:g id="SIZE">%1$s</xliff:g> podataka aplikacije."</string>
diff --git a/packages/PackageInstaller/res/values-hu/strings.xml b/packages/PackageInstaller/res/values-hu/strings.xml
index 6b37633..70ebadb 100644
--- a/packages/PackageInstaller/res/values-hu/strings.xml
+++ b/packages/PackageInstaller/res/values-hu/strings.xml
@@ -56,6 +56,7 @@
     <string name="uninstall_application_text" msgid="3816830743706143980">"Eltávolítja ezt az alkalmazást?"</string>
     <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Szeretné eltávolítani ezt az alkalmazást "<b>"minden"</b>" felhasználónál? Az alkalmazást és adatait az eszköz "<b>"minden"</b>" felhasználójánál töröljük."</string>
     <string name="uninstall_application_text_user" msgid="498072714173920526">"Eltávolítja ezt az alkalmazást <xliff:g id="USERNAME">%1$s</xliff:g> felhasználó esetében?"</string>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Biztosan eltávolítja ezt az alkalmazást a munkaprofiljából?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"Lecseréli az alkalmazást a gyári verzióra? Minden adat törlődik."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Lecseréli az alkalmazást a gyári verzióra? Minden adat törlődik. Ez az eszköz összes felhasználóját érinti, így a munkaprofilokkal rendelkezőket is."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"<xliff:g id="SIZE">%1$s</xliff:g> alkalmazásadat megtartása."</string>
diff --git a/packages/PackageInstaller/res/values-hy/strings.xml b/packages/PackageInstaller/res/values-hy/strings.xml
index 4c2b0ad..288c9b1 100644
--- a/packages/PackageInstaller/res/values-hy/strings.xml
+++ b/packages/PackageInstaller/res/values-hy/strings.xml
@@ -56,6 +56,7 @@
     <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>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Հեռացնե՞լ այս հավելվածը ձեր աշխատանքային պրոֆիլից"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"Փոխարինե՞լ այս հավելվածը գործարանային տարբերակով: Բոլոր տվյալները կհեռացվեն:"</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Փոխարինե՞լ այս հավելվածը գործարանային տարբերակով: Բոլոր տվյալները կհեռացվեն: Դա վերաբերում է այս սարքի բոլոր օգտատերերին, այդ թվում նաև աշխատանքային պրոֆիլներ ունեցողներին:"</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"Չհեռացնել հավելվածների տվյալները (<xliff:g id="SIZE">%1$s</xliff:g>):"</string>
diff --git a/packages/PackageInstaller/res/values-in/strings.xml b/packages/PackageInstaller/res/values-in/strings.xml
index bc368e7..e3e5606 100644
--- a/packages/PackageInstaller/res/values-in/strings.xml
+++ b/packages/PackageInstaller/res/values-in/strings.xml
@@ -56,6 +56,7 @@
     <string name="uninstall_application_text" msgid="3816830743706143980">"Apakah Anda ingin meng-uninstal aplikasi ini?"</string>
     <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Apakah Anda ingin meng-uninstal aplikasi ini untuk "<b>"semua"</b>" pengguna? Aplikasi dan datanya akan dihapus dari "<b>"semua"</b>" pengguna pada perangkat."</string>
     <string name="uninstall_application_text_user" msgid="498072714173920526">"Apakah Anda ingin meng-uninstal aplikasi ini untuk pengguna <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Ingin meng-uninstal aplikasi ini dari profil kerja Anda?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"Ganti aplikasi ini dengan versi setelan pabrik? Semua data akan dihapus."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Ganti aplikasi ini dengan versi setelan pabrik? Semua data akan dihapus. Tindakan ini memengaruhi semua pengguna perangkat ini, termasuk yang memiliki profil kerja."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"Pertahankan data aplikasi sebesar <xliff:g id="SIZE">%1$s</xliff:g>."</string>
diff --git a/packages/PackageInstaller/res/values-is/strings.xml b/packages/PackageInstaller/res/values-is/strings.xml
index 2b2e215..7f0ee04 100644
--- a/packages/PackageInstaller/res/values-is/strings.xml
+++ b/packages/PackageInstaller/res/values-is/strings.xml
@@ -56,6 +56,7 @@
     <string name="uninstall_application_text" msgid="3816830743706143980">"Viltu fjarlægja þetta forrit?"</string>
     <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Viltu fjarlægja þetta forrit hjá "<b>"öllum"</b>" notendum? Forritið og gögn þess verða fjarlægð hjá "<b>"öllum"</b>" notendum tækisins."</string>
     <string name="uninstall_application_text_user" msgid="498072714173920526">"Viltu fjarlægja þetta forrit fyrir notandann <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Viltu fjarlægja þetta forrit af vinnuprófílnum þínum?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"Viltu skipta þessu forriti út fyrir verksmiðjuútgáfuna? Öll gögn verða fjarlægð."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Viltu skipta þessu forriti út fyrir verksmiðjuútgáfuna? Öll gögn verða fjarlægð. Þetta hefur áhrif á alla notendur tækisins, þar á meðal þá sem eru með vinnusnið."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"Halda <xliff:g id="SIZE">%1$s</xliff:g> af forritagögnum."</string>
diff --git a/packages/PackageInstaller/res/values-it/strings.xml b/packages/PackageInstaller/res/values-it/strings.xml
index c554aab..979de60 100644
--- a/packages/PackageInstaller/res/values-it/strings.xml
+++ b/packages/PackageInstaller/res/values-it/strings.xml
@@ -56,6 +56,7 @@
     <string name="uninstall_application_text" msgid="3816830743706143980">"Vuoi disinstallare questa app?"</string>
     <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Vuoi disinstallare questa applicazione per "<b>"tutti"</b>" gli utenti? L\'applicazione e i relativi dati verranno rimossi da "<b>"tutti"</b>" gli utenti configurati sul dispositivo."</string>
     <string name="uninstall_application_text_user" msgid="498072714173920526">"Disinstallare l\'app per l\'utente <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Vuoi disinstallare questa app dal tuo profilo di lavoro?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"Sostituire questa app con la versione di fabbrica? Tutti i dati verranno rimossi."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Sostituire questa app con la versione di fabbrica? Tutti i dati verranno rimossi. Saranno interessati tutti gli utenti del dispositivo, inclusi quelli che hanno profili di lavoro."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"Mantieni <xliff:g id="SIZE">%1$s</xliff:g> di dati delle app."</string>
diff --git a/packages/PackageInstaller/res/values-iw/strings.xml b/packages/PackageInstaller/res/values-iw/strings.xml
index 0351c45..2d7c988 100644
--- a/packages/PackageInstaller/res/values-iw/strings.xml
+++ b/packages/PackageInstaller/res/values-iw/strings.xml
@@ -56,6 +56,7 @@
     <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>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"רוצה להסיר את האפליקציה הזו מפרופיל העבודה?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"להחליף את האפליקציה הזאת בגרסת היצרן? כל הנתונים יוסרו."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"האם להחליף את האפליקציה הזאת בגרסת היצרן? כל הנתונים יוסרו. הפעולה תשפיע על כל משתמשי המכשיר, כולל משתמשים בעלי פרופיל עבודה."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"שמירת <xliff:g id="SIZE">%1$s</xliff:g> מנתוני האפליקציה."</string>
diff --git a/packages/PackageInstaller/res/values-ja/strings.xml b/packages/PackageInstaller/res/values-ja/strings.xml
index 880ff86..8ddc87c 100644
--- a/packages/PackageInstaller/res/values-ja/strings.xml
+++ b/packages/PackageInstaller/res/values-ja/strings.xml
@@ -56,6 +56,7 @@
     <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>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"このアプリを仕事用プロファイルからアンインストールしますか?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"このアプリを出荷時の状態に戻しますか?データがすべて削除されます。"</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"このアプリを出荷時の状態に戻しますか?データがすべて削除されます。これは、仕事用プロファイルを設定しているユーザーも含めて、このデバイスを使用するすべてのユーザーが対象となります。"</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"アプリのデータ(<xliff:g id="SIZE">%1$s</xliff:g>)を保持"</string>
diff --git a/packages/PackageInstaller/res/values-ka/strings.xml b/packages/PackageInstaller/res/values-ka/strings.xml
index 4d83332..ea6d45e 100644
--- a/packages/PackageInstaller/res/values-ka/strings.xml
+++ b/packages/PackageInstaller/res/values-ka/strings.xml
@@ -56,6 +56,7 @@
     <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>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"გსურთ ამ აპის დეინსტალაცია თქვენი სამსახურის პროფილიდან?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"გსურთ ამ აპის ჩანაცვლება ქარხნული ვერსიით? მონაცემები მთლიანად ამოიშლება."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"გსურთ ამ აპის ჩანაცვლება ქარხნული ვერსიით? მონაცემები მთლიანად ამოიშლება. ეს ქმედება აისახება ამ მოწყობილობის ყველა მომხმარებელზე, მათ შორის, სამსახურის პროფილებით მოსარგებლეებზეც."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"შენარჩუნდეს აპების მონაცემების <xliff:g id="SIZE">%1$s</xliff:g>."</string>
diff --git a/packages/PackageInstaller/res/values-kk/strings.xml b/packages/PackageInstaller/res/values-kk/strings.xml
index 964e2c3..20eed5b 100644
--- a/packages/PackageInstaller/res/values-kk/strings.xml
+++ b/packages/PackageInstaller/res/values-kk/strings.xml
@@ -56,6 +56,7 @@
     <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>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Бұл қолданба жұмыс профиліңізден жойылсын ба?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"Осы қолданбаны зауыттық нұсқамен ауыстыру керек пе? Барлық деректер жойылады."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Осы қолданбаны зауыттық нұсқамен ауыстыру керек пе? Барлық деректер жойылады. Бұл осы құрылғының барлық пайдаланушыларына, соның ішінде жұмыс профильдері бар пайдаланушыларға әсер етеді."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"Қолданба деректерін (<xliff:g id="SIZE">%1$s</xliff:g>) сақтау."</string>
diff --git a/packages/PackageInstaller/res/values-km/strings.xml b/packages/PackageInstaller/res/values-km/strings.xml
index 0ca4c12..525e0ef 100644
--- a/packages/PackageInstaller/res/values-km/strings.xml
+++ b/packages/PackageInstaller/res/values-km/strings.xml
@@ -56,6 +56,7 @@
     <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>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"តើអ្នក​ចង់លុប​កម្មវិធីនេះ​ពីកម្រងព័ត៌មាន​ការងាររបស់អ្នក​ដែរទេ?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"ជំនួសកម្មវិធីនេះដោយប្រើកំណែរោងចក្រ? ទិន្នន័យទាំងអស់នឹងត្រូវបានលុប។"</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"ជំនួសកម្មវិធីនេះដោយប្រើកំណែរោងចក្រ? ទិន្នន័យទាំងអស់នឹងត្រូវបានលុប។ សកម្មភាព​នេះប៉ះពាល់ដល់អ្នកប្រើប្រាស់ទាំងអស់​របស់ឧបករណ៍នេះ រួម​ទាំងអ្នកប្រើប្រាស់ដែលមានកម្រង​ព័ត៌មាន​ការងារ​ផងដែរ។"</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"រក្សាទុក​ទិន្នន័យ​កម្មវិធីទំហំ <xliff:g id="SIZE">%1$s</xliff:g>។"</string>
diff --git a/packages/PackageInstaller/res/values-kn/strings.xml b/packages/PackageInstaller/res/values-kn/strings.xml
index 045c481..4c6b2ff 100644
--- a/packages/PackageInstaller/res/values-kn/strings.xml
+++ b/packages/PackageInstaller/res/values-kn/strings.xml
@@ -56,6 +56,7 @@
     <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>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"ನಿಮ್ಮ ಉದ್ಯೋಗದ ಪ್ರೊಫೈಲ್‌ನಿಂದ ಈ ಆ್ಯಪ್‌ ಅನ್ನು ಅನ್‌ಇನ್‌ಸ್ಟಾಲ್ ಮಾಡಲು ನೀವು ಬಯಸುವಿರಾ?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"ಈ ಆ್ಯಪ್‌ ಬದಲಿಗೆ ಫ್ಯಾಕ್ಟರಿ ಆವೃತ್ತಿಯನ್ನು ಬದಲಾಯಿಸುವುದೇ? ಎಲ್ಲಾ ಡೇಟಾ ತೆಗೆದುಹಾಕಲಾಗುತ್ತದೆ."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"ಈ ಆ್ಯಪ್‌ ಬದಲಿಗೆ ಫ್ಯಾಕ್ಟರಿ ಆವೃತ್ತಿಯನ್ನು ಬದಲಾಯಿಸುವುದೇ? ಎಲ್ಲಾ ಡೇಟಾ ತೆಗೆದುಹಾಕಲಾಗುತ್ತದೆ. ಕೆಲಸದ ಪ್ರೊಫೈಲ್‌ಗಳನ್ನು ಹೊಂದಿರುವವುಗಳನ್ನು ಒಳಗೊಂಡಂತೆ ಈ ಸಾಧನದ ಎಲ್ಲಾ ಬಳಕೆದಾರರಿಗೆ ಇದು ಪರಿಣಾಮ ಬೀರುತ್ತದೆ."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"ಆ್ಯಪ್ ಡೇಟಾದಲ್ಲಿ <xliff:g id="SIZE">%1$s</xliff:g> ಇರಿಸಿಕೊಳ್ಳಿ."</string>
diff --git a/packages/PackageInstaller/res/values-ko/strings.xml b/packages/PackageInstaller/res/values-ko/strings.xml
index 1afdc34..02e65ab9 100644
--- a/packages/PackageInstaller/res/values-ko/strings.xml
+++ b/packages/PackageInstaller/res/values-ko/strings.xml
@@ -56,6 +56,7 @@
     <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>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"직장 프로필에서 이 앱을 제거하시겠습니까?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"이 앱을 초기 버전으로 바꾸시겠습니까? 모든 데이터가 삭제됩니다."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"이 앱을 초기 버전으로 바꾸시겠습니까? 모든 데이터가 삭제되며 직장 프로필 사용자를 포함해 이 기기의 모든 사용자에게 영향을 미칩니다."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"앱 데이터 크기를 <xliff:g id="SIZE">%1$s</xliff:g>로 유지합니다."</string>
diff --git a/packages/PackageInstaller/res/values-ky/strings.xml b/packages/PackageInstaller/res/values-ky/strings.xml
index b9ceb08..5adfd2b 100644
--- a/packages/PackageInstaller/res/values-ky/strings.xml
+++ b/packages/PackageInstaller/res/values-ky/strings.xml
@@ -56,6 +56,7 @@
     <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>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Бул колдонмону жумуш профилиңизден чыгарып саласызбы?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"Бул колдонмонун баштапкы версиясы орнотулсунбу? Бардык дайындар өчүп калат."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Бул колдонмонун баштапкы версиясы орнотулсунбу? Түзмөктөгү бардык профилдердин, ошондой эле жумушчу профилдердин дайындары өчүп калат."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"Колдонмонун <xliff:g id="SIZE">%1$s</xliff:g> дайындарын сактоо."</string>
diff --git a/packages/PackageInstaller/res/values-lo/strings.xml b/packages/PackageInstaller/res/values-lo/strings.xml
index 52c8b46..868c35d 100644
--- a/packages/PackageInstaller/res/values-lo/strings.xml
+++ b/packages/PackageInstaller/res/values-lo/strings.xml
@@ -56,6 +56,7 @@
     <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>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"ທ່ານຕ້ອງການຖອນການຕິດຕັ້ງແອັບນີ້ຈາກ​ໂປຣ​ໄຟລ໌​ບ່ອນ​ເຮັດ​ວຽກບໍ?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"ແທນທີ່ແອັບນີ້ດ້ວຍເວີຊັນທີ່ມາຈາກໂຮງງານບໍ? ຂໍ້ມູນທັງໝົດຈະຖືກລຶບອອກ."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"ແທນທີ່ແອັບນີ້ດ້ວຍເວີຊັນທີ່ມາຈາກໂຮງງານບໍ? ຂໍ້ມູນທັງໝົດຈະຖືກລຶບອອກ ເຊິ່ງມີຜົນກັບຜູ້ໃຊ້ອຸປະກອນນີ້ທຸກຄົນ ຮວມທັງຄົນທີ່ມີໂປຣໄຟລ໌ບ່ອນເຮັດວຽກນຳ."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"ຮັກສາຂະໜາດຂໍ້ມູນແອັບ <xliff:g id="SIZE">%1$s</xliff:g> ໄວ້."</string>
diff --git a/packages/PackageInstaller/res/values-lt/strings.xml b/packages/PackageInstaller/res/values-lt/strings.xml
index 5d57b03..4dfbb27 100644
--- a/packages/PackageInstaller/res/values-lt/strings.xml
+++ b/packages/PackageInstaller/res/values-lt/strings.xml
@@ -56,6 +56,7 @@
     <string name="uninstall_application_text" msgid="3816830743706143980">"Ar norite pašalinti šią programą?"</string>
     <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Ar norite pašalinti šią programą "<b>"visiems"</b>" naudotojams? Programa ir jos duomenys bus pašalinti "<b>"visiems"</b>" įrenginio naudotojams."</string>
     <string name="uninstall_application_text_user" msgid="498072714173920526">"Ar norite pašalinti šią naudotojo <xliff:g id="USERNAME">%1$s</xliff:g> programą?"</string>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Ar norite pašalinti šią programą iš savo darbo profilio?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"Pakeisti šios programos versiją į gamyklinę? Visi duomenys bus pašalinti."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Pakeisti šios programos versiją į gamyklinę? Visi duomenys bus pašalinti. Tai paveiks visus šio įrenginio naudotojus, įskaitant turinčius darbo profilius."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"Palikti <xliff:g id="SIZE">%1$s</xliff:g> programų duomenų."</string>
diff --git a/packages/PackageInstaller/res/values-lv/strings.xml b/packages/PackageInstaller/res/values-lv/strings.xml
index c58b293..2a5507f 100644
--- a/packages/PackageInstaller/res/values-lv/strings.xml
+++ b/packages/PackageInstaller/res/values-lv/strings.xml
@@ -56,6 +56,7 @@
     <string name="uninstall_application_text" msgid="3816830743706143980">"Vai vēlaties atinstalēt šo lietotni?"</string>
     <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Vai vēlaties atinstalēt šo lietotni "<b>"visiem"</b>" lietotājiem? Šī lietojumprogramma un tās dati tiks noņemti no "<b>"visiem"</b>" ierīces lietotāju kontiem."</string>
     <string name="uninstall_application_text_user" msgid="498072714173920526">"Vai vēlaties atinstalēt šo lietotni lietotājam <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Vai vēlaties atinstalēt šo lietotni no sava darba profila?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"Vai aizstāt šo lietotni ar rūpnīcas versiju? Visi dati tiks noņemti."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Vai aizstāt šo lietotni ar rūpnīcas versiju? Visi dati tiks noņemti. Tas ietekmēs visu šīs ierīces lietotāju datus, pat ja viņiem ir darba profili."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"Iegūstiet <xliff:g id="SIZE">%1$s</xliff:g> (lietotnes dati)."</string>
diff --git a/packages/PackageInstaller/res/values-mk/strings.xml b/packages/PackageInstaller/res/values-mk/strings.xml
index 4ebe101..732df62 100644
--- a/packages/PackageInstaller/res/values-mk/strings.xml
+++ b/packages/PackageInstaller/res/values-mk/strings.xml
@@ -56,6 +56,7 @@
     <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>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Дали сакате да ја деинсталирате апликацијава од работниот профил?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"Сакате да ја замените оваа апликација со фабричката верзија? Сите податоци ќе се отстранат."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Сакате да ја замените оваа апликација со фабричката верзија? Сите податоци ќе се отстранат. Тоа важи за сите корисници на овој уред, вклучувајќи ги и тие со работни профили."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"Задржи <xliff:g id="SIZE">%1$s</xliff:g> податоци на апликацијата."</string>
diff --git a/packages/PackageInstaller/res/values-ml/strings.xml b/packages/PackageInstaller/res/values-ml/strings.xml
index 0d24f87..66de3f1 100644
--- a/packages/PackageInstaller/res/values-ml/strings.xml
+++ b/packages/PackageInstaller/res/values-ml/strings.xml
@@ -56,6 +56,7 @@
     <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>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"നിങ്ങളുടെ ഔദ്യോഗിക പ്രൊഫൈലിൽ നിന്ന് ഈ ആപ്പ് അൺ ഇൻസ്‌റ്റാൾ ചെയ്യണോ?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"ഫാക്‌ടറി പതിപ്പ് ഉപയോഗിച്ച് ഈ ആപ്പിന് പകരം വയ്ക്കണോ? എല്ലാ ഡാറ്റയും നീക്കം ചെയ്യപ്പെടും."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"ഫാക്‌ടറി പതിപ്പ് ഉപയോഗിച്ച് ഈ ആപ്പിന് പകരം വയ്ക്കണോ? എല്ലാ ഡാറ്റയും നീക്കം ചെയ്യപ്പെടും. ഔദ്യോഗിക പ്രൊഫൈലുകൾ ഉള്ളവർ ഉൾപ്പെടെ, ഈ ഉപകരണത്തിന്റെ എല്ലാ ഉപയോക്താക്കളെയും ഇത് ബാധിക്കും."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"<xliff:g id="SIZE">%1$s</xliff:g> ആപ്പ് ഡാറ്റ വയ്ക്കുക."</string>
diff --git a/packages/PackageInstaller/res/values-mn/strings.xml b/packages/PackageInstaller/res/values-mn/strings.xml
index 3f49e8c..5eb0e6c 100644
--- a/packages/PackageInstaller/res/values-mn/strings.xml
+++ b/packages/PackageInstaller/res/values-mn/strings.xml
@@ -56,6 +56,7 @@
     <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>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Та энэ аппыг ажлын профайлаасаа устгахыг хүсэж байна уу?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"Энэ аппыг үйлдвэрээс ирсэн хувилбараар солих уу? Бүх өгөгдөл устах болно."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Энэ аппыг үйлдвэрээс ирсэн хувилбараар солих уу? Бүх өгөгдөл устах болно. Энэ нь эдгээр ажлын профайлтай бүхий энэ төхөөрөмжийн бүх хэрэглэгчид нөлөөлнө."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"Аппын өгөгдлийн <xliff:g id="SIZE">%1$s</xliff:g>-г үлдээнэ үү."</string>
diff --git a/packages/PackageInstaller/res/values-mr/strings.xml b/packages/PackageInstaller/res/values-mr/strings.xml
index e5adc8a..42a9676 100644
--- a/packages/PackageInstaller/res/values-mr/strings.xml
+++ b/packages/PackageInstaller/res/values-mr/strings.xml
@@ -56,6 +56,7 @@
     <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>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"तुम्हाला तुमच्या कार्य प्रोफाइलमधून हे ॲप अनइंस्टॉल करायचे आहे का?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"फॅक्टरी आवृत्तीसह हे अ‍ॅप बदलायचे का? सर्व डेटा काढला जाईल."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"फॅक्टरी आवृत्तीसह हे अ‍ॅप बदलायचे? सर्व डेटा काढला जाईल. हे कार्य प्रोफाइल असलेल्यांसह या डिव्हाइसच्या सर्व वापरकर्त्यांना प्रभावित करते."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"ॲप डेटा पैकी <xliff:g id="SIZE">%1$s</xliff:g> ठेवा."</string>
diff --git a/packages/PackageInstaller/res/values-ms/strings.xml b/packages/PackageInstaller/res/values-ms/strings.xml
index 3adfe88..09ed820 100644
--- a/packages/PackageInstaller/res/values-ms/strings.xml
+++ b/packages/PackageInstaller/res/values-ms/strings.xml
@@ -56,6 +56,7 @@
     <string name="uninstall_application_text" msgid="3816830743706143980">"Adakah anda mahu menyahpasang apl ini?"</string>
     <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Adakah anda mahu menyahpasang apl ini untuk "<b>"semua"</b>" pengguna? Aplikasi dan datanya akan dialih keluar daripada "<b>"semua"</b>" pengguna pada peranti."</string>
     <string name="uninstall_application_text_user" msgid="498072714173920526">"Adakah anda ingin menyahpasang apl ini untuk pengguna <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Adakah anda mahu menyahpasang apl ini daripada profil kerja anda?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"Gantikan apl ini dengan versi kilang? Semua data akan dialih keluar."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Gantikan apl ini dengan versi kilang? Semua data akan dialih keluar. Tindakan ini melibatkan semua pengguna peranti ini, termasuk mereka yang mempunyai profil kerja."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"Simpan <xliff:g id="SIZE">%1$s</xliff:g> data apl."</string>
diff --git a/packages/PackageInstaller/res/values-my/strings.xml b/packages/PackageInstaller/res/values-my/strings.xml
index e0fa952..d6e72d6 100644
--- a/packages/PackageInstaller/res/values-my/strings.xml
+++ b/packages/PackageInstaller/res/values-my/strings.xml
@@ -56,6 +56,7 @@
     <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>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"သင့်အလုပ်ပရိုဖိုင်ကနေ ဤအက်ပ်ကို ဖယ်ရှားလိုတာ သေချာပါသလား။"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"ဤအက်ပ်ကို စက်ရုံထုတ်ဗားရှင်းဖြင့် အစားထိုးလိုပါသလား။ ဒေတာများအားလုံးကို ဖယ်ရှားလိုက်ပါမည်။"</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"ဤအက်ပ်ကို စက်ရုံထုတ်ဗားရှင်းဖြင့် အစားထိုးလိုသလား။ ဒေတာများအားလုံးကို ဖယ်ရှားလိုက်ပါမည်။ ၎င်းသည် အလုပ်ပရိုဖိုင်ဖြင့်သုံးသူများအပါအဝင် အသုံးပြုသူများအားလုံးကို အကျိုးသက်ရောက်စေပါမည်။"</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"အက်ပ်ဒေတာများ၏ <xliff:g id="SIZE">%1$s</xliff:g> ကို ထားရှိရန်။"</string>
diff --git a/packages/PackageInstaller/res/values-nb/strings.xml b/packages/PackageInstaller/res/values-nb/strings.xml
index e382620..a0a00b3 100644
--- a/packages/PackageInstaller/res/values-nb/strings.xml
+++ b/packages/PackageInstaller/res/values-nb/strings.xml
@@ -56,6 +56,7 @@
     <string name="uninstall_application_text" msgid="3816830743706143980">"Vil du avinstallere denne appen?"</string>
     <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Vil du avinstallere denne appen for "<b>"alle"</b>" brukere? Appen og tilhørende data blir fjernet fra "<b>"alle"</b>" brukere på enheten."</string>
     <string name="uninstall_application_text_user" msgid="498072714173920526">"Ønsker du å avinstallere denne appen for brukeren <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Vil du avinstallere denne appen fra jobbprofilen din?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"Vil du erstatte denne appen med den opprinnelige versjonen? Alle dataene fjernes."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Vil du erstatte denne appen med den opprinnelige versjonen? Alle dataene fjernes. Dette påvirker alle som bruker denne enheten – også personer med jobbprofiler."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"Behold <xliff:g id="SIZE">%1$s</xliff:g> med appdata."</string>
diff --git a/packages/PackageInstaller/res/values-ne/strings.xml b/packages/PackageInstaller/res/values-ne/strings.xml
index 5509c1c..ec9c60e 100644
--- a/packages/PackageInstaller/res/values-ne/strings.xml
+++ b/packages/PackageInstaller/res/values-ne/strings.xml
@@ -56,6 +56,7 @@
     <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>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"तपाईं आफ्नो कार्य प्रोफाइलबाट यो एप अनइन्स्टल गर्न चाहनुहुन्छ?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"यस एपलाई फ्याक्ट्रीको संस्करणले बदल्ने हो? सबै डेटा हटाइने छ।"</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"यस एपलाई फ्याक्ट्रीको संस्करणले बदल्ने हो? सबै डेटा हटाइने छ। यसले यस डिभाइसका कार्य प्रोफाइल भएका लगायत सबै प्रयोगकर्ताहरूमा असर पार्छ।"</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"<xliff:g id="SIZE">%1$s</xliff:g> एपको डेटा राख्नुहोस्।"</string>
diff --git a/packages/PackageInstaller/res/values-nl/strings.xml b/packages/PackageInstaller/res/values-nl/strings.xml
index ea675b1..8afe5db 100644
--- a/packages/PackageInstaller/res/values-nl/strings.xml
+++ b/packages/PackageInstaller/res/values-nl/strings.xml
@@ -56,6 +56,7 @@
     <string name="uninstall_application_text" msgid="3816830743706143980">"Wil je deze app verwijderen?"</string>
     <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Wil je deze app verwijderen voor "<b>"alle"</b>" gebruikers? Deze app en de gegevens ervan worden verwijderd voor "<b>"alle"</b>" gebruikers van het apparaat."</string>
     <string name="uninstall_application_text_user" msgid="498072714173920526">"Wil je deze app verwijderen voor de gebruiker <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Wil je deze app verwijderen uit je werkprofiel?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"Deze app vervangen door de fabrieksversie? Alle gegevens worden verwijderd."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Deze app vervangen door de fabrieksversie? Alle gegevens worden verwijderd. Dit geldt voor alle gebruikers van het apparaat, dus ook voor gebruikers met een werkprofiel."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"<xliff:g id="SIZE">%1$s</xliff:g> aan app-gegevens behouden."</string>
diff --git a/packages/PackageInstaller/res/values-or/strings.xml b/packages/PackageInstaller/res/values-or/strings.xml
index 3ea1e99..20a3480 100644
--- a/packages/PackageInstaller/res/values-or/strings.xml
+++ b/packages/PackageInstaller/res/values-or/strings.xml
@@ -56,6 +56,7 @@
     <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>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"ଆପଣ ଆପଣଙ୍କ ୱାର୍କ ପ୍ରୋଫାଇଲରୁ ଏହି ଆପକୁ ଅନଇନଷ୍ଟଲ କରିବାକୁ ଚାହାଁନ୍ତି କି?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"ଏହି ଆପ୍‍ ଫ୍ୟାକ୍ଟୋରୀ ଭର୍ସନ୍‍‍ ସହ ବଦଳାଇବେ? ସମସ୍ତ ଡାଟା କାଢ଼ିଦିଆଯିବ।"</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"ଏହି ଆପ୍‍ ଫ୍ୟାକ୍ଟୋରୀ ଭର୍ସନ୍‍‍ ସହ ବଦଳାଇବେ? ସମସ୍ତ ଡାଟା ବାହାର କରିଦିଆଯିବ। ୱର୍କ ପ୍ରୋଫାଇଲ୍‍ ଥିବା ସମେତ, ଏହାଦ୍ୱାରା ଡିଭାଇସରେ ଥିବା ସମସ୍ତ ୟୁଜର୍‌ ପ୍ରଭାବିତ ହେବେ।"</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"<xliff:g id="SIZE">%1$s</xliff:g> ଆକାରର ଆପ୍‍ ଡାଟା ରଖନ୍ତୁୁ।"</string>
diff --git a/packages/PackageInstaller/res/values-pa/strings.xml b/packages/PackageInstaller/res/values-pa/strings.xml
index 0d44440..d5b8573 100644
--- a/packages/PackageInstaller/res/values-pa/strings.xml
+++ b/packages/PackageInstaller/res/values-pa/strings.xml
@@ -56,6 +56,7 @@
     <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>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"ਕੀ ਤੁਸੀਂ ਇਸ ਐਪ ਨੂੰ ਆਪਣੇ ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਤੋਂ ਅਣਸਥਾਪਤ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"ਕੀ ਇਸ ਐਪ ਨੂੰ ਫੈਕਟਰੀ ਵਰਜਨ ਨਾਲ ਬਦਲਣਾ ਹੈ? ਸਾਰਾ ਡਾਟਾ ਹਟਾ ਦਿੱਤਾ ਜਾਵੇਗਾ।"</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"ਕੀ ਇਸ ਐਪ ਨੂੰ ਫੈਕਟਰੀ ਵਰਜਨ ਨਾਲ ਬਦਲਣਾ ਹੈ? ਸਾਰਾ ਡਾਟਾ ਹਟਾ ਦਿੱਤਾ ਜਾਵੇਗਾ। ਇਹ ਇਸ ਡੀਵਾਈਸ ਦੇ ਸਾਰੇ ਵਰਤੋਂਕਾਰਾਂ ਨੂੰ ਪ੍ਰਭਾਵਿਤ ਕਰੇਗਾ, ਜਿਸ ਵਿੱਚ ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਵਾਲੇ ਵਰਤੋਂਕਾਰ ਵੀ ਸ਼ਾਮਲ ਹਨ।"</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"<xliff:g id="SIZE">%1$s</xliff:g> ਐਪ ਡਾਟਾ ਰੱਖੋ।"</string>
diff --git a/packages/PackageInstaller/res/values-pl/strings.xml b/packages/PackageInstaller/res/values-pl/strings.xml
index 9fd3ada..e0b8637 100644
--- a/packages/PackageInstaller/res/values-pl/strings.xml
+++ b/packages/PackageInstaller/res/values-pl/strings.xml
@@ -56,6 +56,7 @@
     <string name="uninstall_application_text" msgid="3816830743706143980">"Odinstalować tę aplikację?"</string>
     <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Chcesz odinstalować tę aplikację dla "<b>"wszystkich"</b>" użytkowników? Ta aplikacja i jej dane zostaną usunięte dla "<b>"wszystkich"</b>" użytkowników na urządzeniu."</string>
     <string name="uninstall_application_text_user" msgid="498072714173920526">"Chcesz odinstalować tę aplikację dla użytkownika <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Czy chcesz odinstalować tę aplikację z profilu służbowego?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"Przywrócić fabryczną wersję tej aplikacji? Wszystkie dane zostaną usunięte."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Przywrócić fabryczną wersję tej aplikacji? Wszystkie dane zostaną usunięte. Dotyczy to wszystkich użytkowników tego urządzenia, również tych korzystających z profilu służbowego."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"Zachowaj <xliff:g id="SIZE">%1$s</xliff:g> danych aplikacji."</string>
diff --git a/packages/PackageInstaller/res/values-pt-rBR/strings.xml b/packages/PackageInstaller/res/values-pt-rBR/strings.xml
index 2111b87..098c4b0 100644
--- a/packages/PackageInstaller/res/values-pt-rBR/strings.xml
+++ b/packages/PackageInstaller/res/values-pt-rBR/strings.xml
@@ -56,6 +56,7 @@
     <string name="uninstall_application_text" msgid="3816830743706143980">"Quer desinstalar este app?"</string>
     <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Quer desinstalar este app para "<b>"todos"</b>" os usuários? O aplicativo e os dados dele serão removidos para "<b>"todos"</b>" os usuários do dispositivo."</string>
     <string name="uninstall_application_text_user" msgid="498072714173920526">"Quer desinstalar este app para o usuário <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Você quer desinstalar esse app do seu perfil de trabalho?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"Substituir este app pela versão de fábrica? Todos os dados serão removidos."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Substituir este app pela versão de fábrica? Todos os dados serão removidos. Isso afeta todos os usuários deste dispositivo, incluindo aqueles com perfis de trabalho."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"Manter <xliff:g id="SIZE">%1$s</xliff:g> de dados do app."</string>
diff --git a/packages/PackageInstaller/res/values-pt-rPT/strings.xml b/packages/PackageInstaller/res/values-pt-rPT/strings.xml
index 9689415..9e3b40d 100644
--- a/packages/PackageInstaller/res/values-pt-rPT/strings.xml
+++ b/packages/PackageInstaller/res/values-pt-rPT/strings.xml
@@ -56,6 +56,7 @@
     <string name="uninstall_application_text" msgid="3816830743706143980">"Pretende desinstalar esta app?"</string>
     <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Pretende desinstalar esta app para "<b>"todos"</b>" os utilizadores? A app e os respetivos dados serão removidos de "<b>"todos"</b>" os utilizadores do dispositivo."</string>
     <string name="uninstall_application_text_user" msgid="498072714173920526">"Pretende desinstalar esta app para o utilizador <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Quer desinstalar esta app do seu perfil de trabalho?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"Pretende substituir esta app pela versão de fábrica? Todos os dados são removidos."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Pretende substituir esta app pela versão de fábrica? Todos os dados são removidos. Esta ação afeta todos os utilizadores deste dispositivo, incluindo os que têm perfis de trabalho."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"Manter <xliff:g id="SIZE">%1$s</xliff:g> de dados da app."</string>
diff --git a/packages/PackageInstaller/res/values-pt/strings.xml b/packages/PackageInstaller/res/values-pt/strings.xml
index 2111b87..098c4b0 100644
--- a/packages/PackageInstaller/res/values-pt/strings.xml
+++ b/packages/PackageInstaller/res/values-pt/strings.xml
@@ -56,6 +56,7 @@
     <string name="uninstall_application_text" msgid="3816830743706143980">"Quer desinstalar este app?"</string>
     <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Quer desinstalar este app para "<b>"todos"</b>" os usuários? O aplicativo e os dados dele serão removidos para "<b>"todos"</b>" os usuários do dispositivo."</string>
     <string name="uninstall_application_text_user" msgid="498072714173920526">"Quer desinstalar este app para o usuário <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Você quer desinstalar esse app do seu perfil de trabalho?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"Substituir este app pela versão de fábrica? Todos os dados serão removidos."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Substituir este app pela versão de fábrica? Todos os dados serão removidos. Isso afeta todos os usuários deste dispositivo, incluindo aqueles com perfis de trabalho."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"Manter <xliff:g id="SIZE">%1$s</xliff:g> de dados do app."</string>
diff --git a/packages/PackageInstaller/res/values-ro/strings.xml b/packages/PackageInstaller/res/values-ro/strings.xml
index 5627c29..03cb145 100644
--- a/packages/PackageInstaller/res/values-ro/strings.xml
+++ b/packages/PackageInstaller/res/values-ro/strings.xml
@@ -56,6 +56,7 @@
     <string name="uninstall_application_text" msgid="3816830743706143980">"Doriți să dezinstalați această aplicație?"</string>
     <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Doriți să dezinstalați această aplicație pentru "<b>"toți"</b>" utilizatorii? Aplicația și datele acesteia vor fi eliminate de la "<b>"toți"</b>" utilizatorii de pe acest dispozitiv."</string>
     <string name="uninstall_application_text_user" msgid="498072714173920526">"Dezinstalați această aplicație pentru utilizatorul <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Doriți să dezinstalați această aplicație din profilul de serviciu?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"Înlocuiți această aplicație cu versiunea din fabrică? Toate datele vor fi eliminate."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Înlocuiți această aplicație cu versiunea din fabrică? Toate datele vor fi eliminate. Această acțiune va afecta toți utilizatorii dispozitivului, inclusiv pe cei cu profiluri de serviciu."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"Păstrează <xliff:g id="SIZE">%1$s</xliff:g> din datele aplicației."</string>
diff --git a/packages/PackageInstaller/res/values-ru/strings.xml b/packages/PackageInstaller/res/values-ru/strings.xml
index f277eca..e0cc4ab2 100644
--- a/packages/PackageInstaller/res/values-ru/strings.xml
+++ b/packages/PackageInstaller/res/values-ru/strings.xml
@@ -56,6 +56,7 @@
     <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>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Удалить это приложение из рабочего профиля?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"Установить исходную версию приложения? Все его данные будут удалены."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Установить исходную версию приложения? Его данные будут удалены из всех профилей устройства, в том числе рабочих."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"Сохранить данные приложения (<xliff:g id="SIZE">%1$s</xliff:g>)"</string>
diff --git a/packages/PackageInstaller/res/values-si/strings.xml b/packages/PackageInstaller/res/values-si/strings.xml
index 4b941bb..fb2344e 100644
--- a/packages/PackageInstaller/res/values-si/strings.xml
+++ b/packages/PackageInstaller/res/values-si/strings.xml
@@ -56,6 +56,7 @@
     <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>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"ඔබට කාර්යාල පැතිකඩ වෙතින් මෙම යෙදුම අස්ථාපනය කිරීමට අවශ්‍යද?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"මෙම යෙදුම කර්මාන්ත ශාලා අනුවාදයක් සමගින් ප්‍රතිස්ථාපනය කරන්නද? සියලු දත්ත ඉවත් කරනු ඇත."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"මෙම යෙදුම කර්මාන්ත ශාලා අනුවාදයක් සමගින් ප්‍රතිස්ථාපනය කරන්නද? සියලු දත්ත ඉවත් කරනු ඇත. මෙය කාර්යාල පැතිකඩවල් සහිත අය ඇතුළුව, මෙම උපාංගයෙහි සියලු පරිශීලකයන් වෙත බලපානු ඇත."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"යෙදුම් දත්තවලින් <xliff:g id="SIZE">%1$s</xliff:g> තබා ගන්න."</string>
diff --git a/packages/PackageInstaller/res/values-sk/strings.xml b/packages/PackageInstaller/res/values-sk/strings.xml
index 10aa411..88ade43 100644
--- a/packages/PackageInstaller/res/values-sk/strings.xml
+++ b/packages/PackageInstaller/res/values-sk/strings.xml
@@ -56,6 +56,7 @@
     <string name="uninstall_application_text" msgid="3816830743706143980">"Chcete túto aplikáciu odinštalovať?"</string>
     <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Chcete odinštalovať túto aplikáciu pre "<b>"všetkých"</b>" používateľov? Aplikácia a jej údaje sa odstránia z tohto zariadenia pre "<b>"všetkých"</b>" používateľov."</string>
     <string name="uninstall_application_text_user" msgid="498072714173920526">"Chcete túto aplikáciu odinštalovať pre používateľa <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Chcete túto aplikáciu odinštalovať zo svojho pracovného profilu?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"Nahradiť túto aplikáciu výrobnou verziou? Všetky údaje sa odstránia."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Nahradiť túto aplikáciu výrobnou verziou? Všetky údaje sa odstránia. Ovplyvní to všetkých používateľov tohto zariadenia vrátane tých s pracovnými profilmi."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"Zachovať nasledujúcu veľkosť dát aplikácie: <xliff:g id="SIZE">%1$s</xliff:g>."</string>
diff --git a/packages/PackageInstaller/res/values-sl/strings.xml b/packages/PackageInstaller/res/values-sl/strings.xml
index a1e56fe..6e5c167 100644
--- a/packages/PackageInstaller/res/values-sl/strings.xml
+++ b/packages/PackageInstaller/res/values-sl/strings.xml
@@ -56,6 +56,7 @@
     <string name="uninstall_application_text" msgid="3816830743706143980">"Ali želite odmestiti to aplikacijo?"</string>
     <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Ali želite odstraniti aplikacijo za "<b>"vse"</b>" uporabnike? Aplikacija in njeni podatki bodo odstranjeni iz "<b>"vseh"</b>" uporabnikov v napravi."</string>
     <string name="uninstall_application_text_user" msgid="498072714173920526">"Ali želite to aplikacijo odstraniti za uporabnika <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Ali želite to aplikacijo odmestiti iz delovnega profila?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"Želite to aplikacijo nadomestiti s tovarniško različico? Odstranjeni bodo vsi podatki."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Želite to aplikacijo nadomestiti s tovarniško različico? Odstranjeni bodo vsi podatki. To vpliva na vse uporabnike te naprave, vključno s tistimi z delovnimi profili."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"Obdrži <xliff:g id="SIZE">%1$s</xliff:g> podatkov aplikacije."</string>
diff --git a/packages/PackageInstaller/res/values-sq/strings.xml b/packages/PackageInstaller/res/values-sq/strings.xml
index f7dca91..b8ada36 100644
--- a/packages/PackageInstaller/res/values-sq/strings.xml
+++ b/packages/PackageInstaller/res/values-sq/strings.xml
@@ -56,6 +56,7 @@
     <string name="uninstall_application_text" msgid="3816830743706143980">"Dëshiron ta çinstalosh këtë aplikacion?"</string>
     <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Dëshiron ta çinstalosh këtë aplikacion për "<b>"të gjithë"</b>" përdoruesit? Aplikacioni dhe të dhënat e tij do të hiqen nga "<b>"të gjithë"</b>" përdoruesit e pajisjes."</string>
     <string name="uninstall_application_text_user" msgid="498072714173920526">"Dëshiron ta çinstalosh këtë aplikacion për përdoruesin <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Dëshiron ta çinstalosh këtë aplikacion nga profili yt i punës?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"Të zëvendësohet ky aplikacion me versionin e fabrikës? Të gjitha të dhënat do të hiqen."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Të zëvendësohet ky aplikacion me versionin e fabrikës? Të gjitha të dhënat do të hiqen. Kjo ndikon te të gjithë përdoruesit e kësaj pajisjeje, duke përfshirë ata me profile të punës."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"Mbaj <xliff:g id="SIZE">%1$s</xliff:g> nga të dhënat e aplikacionit."</string>
diff --git a/packages/PackageInstaller/res/values-sr/strings.xml b/packages/PackageInstaller/res/values-sr/strings.xml
index c6d5279..0f5252a 100644
--- a/packages/PackageInstaller/res/values-sr/strings.xml
+++ b/packages/PackageInstaller/res/values-sr/strings.xml
@@ -56,6 +56,7 @@
     <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>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Да ли желите да деинсталирате ову апликацију са пословног профила?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"Желите ли да замените ову апликацију фабричком верзијом? Сви подаци ће бити уклоњени."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Желите ли да замените ову апликацију фабричком верзијом? Сви подаци ће бити уклоњени. Ово утиче на све кориснике овог уређаја, укључујући и оне са пословним профилима."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"Задржи <xliff:g id="SIZE">%1$s</xliff:g> података апликације."</string>
diff --git a/packages/PackageInstaller/res/values-sv/strings.xml b/packages/PackageInstaller/res/values-sv/strings.xml
index c64c02f..231e3e1 100644
--- a/packages/PackageInstaller/res/values-sv/strings.xml
+++ b/packages/PackageInstaller/res/values-sv/strings.xml
@@ -56,6 +56,7 @@
     <string name="uninstall_application_text" msgid="3816830743706143980">"Vill du avinstallera appen?"</string>
     <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Vill du avinstallera den här appen för "<b>"alla"</b>" användare? Appen och alla data i den tas bort från "<b>"alla"</b>" användare på enheten."</string>
     <string name="uninstall_application_text_user" msgid="498072714173920526">"Vill du avinstallera appen för användaren <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Vill du avinstallera appen från jobbprofilen?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"Vill du ersätta den här appen med den version som var installerad när enheten var ny? All information tas bort."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Vill du ersätta den här appen med den version som var installerad när enheten var ny? All information tas bort. Detta påverkar alla som använder enheten, även dem med jobbprofiler."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"Behåll <xliff:g id="SIZE">%1$s</xliff:g> appdata."</string>
diff --git a/packages/PackageInstaller/res/values-sw/strings.xml b/packages/PackageInstaller/res/values-sw/strings.xml
index 5c2ec6e..65b785f 100644
--- a/packages/PackageInstaller/res/values-sw/strings.xml
+++ b/packages/PackageInstaller/res/values-sw/strings.xml
@@ -56,6 +56,7 @@
     <string name="uninstall_application_text" msgid="3816830743706143980">"Ungependa kuondoa programu hii?"</string>
     <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Je, ungependa kuondoa programu hii kwa watumiaji "<b>"wote"</b>"? Programu na data yake zitaondolewa kutoka kwa watumiaji "<b>"wote"</b>" kwenye kifaa."</string>
     <string name="uninstall_application_text_user" msgid="498072714173920526">"Je, ungependa kuondoa programu hii kwa mtumiaji <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Ungependa kuondoa programu hii kwenye wasifu wako wa kazini?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"Ungependa kubadilisha programu hii na toleo la kiwandani? Data yote itaondolewa."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Ungependa kubadilisha programu hii na toleo la kiwandani? Data yote itaondolewa. Hatua hii itaathiri watumiaji wote wa kifaa hiki, ikiwa ni pamoja na wale walio na wasifu za kazini."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"Dumisha <xliff:g id="SIZE">%1$s</xliff:g> ya data ya programu."</string>
diff --git a/packages/PackageInstaller/res/values-ta/strings.xml b/packages/PackageInstaller/res/values-ta/strings.xml
index 4493a41..62e531a 100644
--- a/packages/PackageInstaller/res/values-ta/strings.xml
+++ b/packages/PackageInstaller/res/values-ta/strings.xml
@@ -56,6 +56,7 @@
     <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>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"உங்கள் பணிக் கணக்கிலிருந்து இந்த ஆப்ஸை நிறுவல் நீக்க விரும்புகிறீர்களா?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"ஆரம்பநிலைப் பதிப்புக்கு இந்த ஆப்ஸை மாற்றியமைக்கவா? அனைத்துத் தரவும் அகற்றப்படும்."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"ஆரம்பநிலைப் பதிப்புக்கு இந்த ஆப்ஸை மாற்றியமைக்கவா? அனைத்துத் தரவும் அகற்றப்படும். பணிக் கணக்குகளுடன் உள்ளவர்கள் உட்பட இந்தச் சாதனத்தின் அனைத்துப் பயனர்களையும் இது பாதிக்கும்."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"<xliff:g id="SIZE">%1$s</xliff:g> ஆப்ஸ் தரவை வைத்திரு."</string>
diff --git a/packages/PackageInstaller/res/values-te/strings.xml b/packages/PackageInstaller/res/values-te/strings.xml
index 33543fd..57c2024 100644
--- a/packages/PackageInstaller/res/values-te/strings.xml
+++ b/packages/PackageInstaller/res/values-te/strings.xml
@@ -56,6 +56,7 @@
     <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>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"మీ వర్క్ ప్రొఫైల్ నుండి ఈ యాప్‌ను మీరు అన్‌ఇన్‌స్టాల్ చేయాలనుకుంటున్నారా?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"ఈ యాప్‌ను ఫ్యాక్టరీ వెర్షన్‌తో భర్తీ చేయాలా? మొత్తం డేటా తీసివేయబడుతుంది."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"ఈ యాప్‌ను ఫ్యాక్టరీ వెర్షన్‌తో భర్తీ చేయాలా? మొత్తం డేటా తీసివేయబడుతుంది. దీని ప్రభావం కార్యాలయ ప్రొఫైల్‌లు కలిగి ఉన్నవారితో సహా ఈ పరికర వినియోగదారులందరిపై ఉంటుంది."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"<xliff:g id="SIZE">%1$s</xliff:g> యాప్ డేటాని ఉంచండి."</string>
diff --git a/packages/PackageInstaller/res/values-th/strings.xml b/packages/PackageInstaller/res/values-th/strings.xml
index 5b15f0b..409672b 100644
--- a/packages/PackageInstaller/res/values-th/strings.xml
+++ b/packages/PackageInstaller/res/values-th/strings.xml
@@ -56,6 +56,7 @@
     <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>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"คุณต้องการถอนการติดตั้งแอปนี้จากโปรไฟล์งานใช่ไหม"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"แทนที่แอปนี้ด้วยเวอร์ชันเริ่มต้นไหม ระบบจะนำข้อมูลทั้งหมดออก"</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"แทนที่แอปนี้ด้วยเวอร์ชันเริ่มต้นไหม ระบบจะนำข้อมูลทั้งหมดออก วิธีนี้จะส่งผลต่อผู้ใช้ทุกคนที่ใช้อุปกรณ์เครื่องนี้ รวมทั้งผู้ที่มีโปรไฟล์งาน"</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"เก็บข้อมูลแอปไว้ <xliff:g id="SIZE">%1$s</xliff:g>"</string>
diff --git a/packages/PackageInstaller/res/values-tl/strings.xml b/packages/PackageInstaller/res/values-tl/strings.xml
index 6b992f6..5606eb5 100644
--- a/packages/PackageInstaller/res/values-tl/strings.xml
+++ b/packages/PackageInstaller/res/values-tl/strings.xml
@@ -56,6 +56,7 @@
     <string name="uninstall_application_text" msgid="3816830743706143980">"Gusto mo bang i-uninstall ang app na ito?"</string>
     <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Gusto mo bang i-uninstall ang app na ito para sa "<b>"lahat"</b>" ng user? Aalisin ang application at ang data nito sa "<b>"lahat"</b>" ng user sa device."</string>
     <string name="uninstall_application_text_user" msgid="498072714173920526">"Gusto mo bang i-uninstall ang app na ito para sa user na si <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Gusto mo bang i-uninstall ang app na ito sa iyong profile sa trabaho?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"Gusto mo bang palitan ang app na ito ng factory na bersyon? Maaalis ang lahat ng data."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Gusto mo bang palitan ang app na ito ng factory na bersyon? Maaalis ang lahat ng data. Nakakaapekto ito sa lahat ng user ng device na ito, kabilang ang mga may profile sa trabaho."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"Panatilihin ang <xliff:g id="SIZE">%1$s</xliff:g> ng data ng app."</string>
diff --git a/packages/PackageInstaller/res/values-tr/strings.xml b/packages/PackageInstaller/res/values-tr/strings.xml
index 81dc24f..673511c 100644
--- a/packages/PackageInstaller/res/values-tr/strings.xml
+++ b/packages/PackageInstaller/res/values-tr/strings.xml
@@ -56,6 +56,7 @@
     <string name="uninstall_application_text" msgid="3816830743706143980">"Bu uygulamanın yüklemesini kaldırmak istiyor musunuz?"</string>
     <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Bu uygulamanın yüklemesini "<b>"tüm"</b>" kullanıcılar için kaldırmak istiyor musunuz? Uygulama ve verileri cihazdan "<b>"tüm"</b>" kullanıcılar için kaldırılacaktır."</string>
     <string name="uninstall_application_text_user" msgid="498072714173920526">"<xliff:g id="USERNAME">%1$s</xliff:g> adlı kullanıcı için bu uygulamanın yüklemesini kaldırmak istiyor musunuz?"</string>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Bu uygulamanın iş profilinizdeki yüklemesini kaldırmak istiyor musunuz?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"Bu uygulamayı fabrika sürümüyle değiştirmek istiyor musunuz? Tüm veriler silinecektir."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Bu uygulamayı fabrika sürümüyle değiştirmek istiyor musunuz? Tüm veriler silinecektir. Bu, çalışma profilleri olan kullanıcılar da dahil olmak üzere cihazı kullanan tüm kullanıcıları etkiler."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"Uygulama verilerinin <xliff:g id="SIZE">%1$s</xliff:g> kadarını sakla."</string>
diff --git a/packages/PackageInstaller/res/values-uk/strings.xml b/packages/PackageInstaller/res/values-uk/strings.xml
index 44a496d..2169b17 100644
--- a/packages/PackageInstaller/res/values-uk/strings.xml
+++ b/packages/PackageInstaller/res/values-uk/strings.xml
@@ -56,6 +56,7 @@
     <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>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Видалити цей додаток із вашого робочого профілю?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"Відновити заводську версію цього додатка? Усі дані буде видалено."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Відновити заводську версію цього додатка? Усі дані буде видалено. Це вплине на всіх користувачів цього пристрою, зокрема на користувачів із робочими профілями."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"Залишити <xliff:g id="SIZE">%1$s</xliff:g> даних додатка."</string>
diff --git a/packages/PackageInstaller/res/values-ur/strings.xml b/packages/PackageInstaller/res/values-ur/strings.xml
index afe46997..57fc568 100644
--- a/packages/PackageInstaller/res/values-ur/strings.xml
+++ b/packages/PackageInstaller/res/values-ur/strings.xml
@@ -56,6 +56,7 @@
     <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>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"کیا آپ اپنے دفتری پروفائل سے یہ ایپ اَن انسٹال کرنا چاہتے ہیں؟"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"اس ایپ کو فیکٹری ورژن سے تبدیل کریں؟ تمام ڈیٹا ہٹا دیا جائے گا۔"</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"اس ایپ کو فیکٹری ورژن سے تبدیل کریں؟ تمام ڈیٹا ہٹا دیا جائے گا۔ اس سے دفتری پروفائلز کے حاملین سمیت اس آلہ کے تمام صارفین متاثر ہوں گے۔"</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"ایپ ڈیٹا کا <xliff:g id="SIZE">%1$s</xliff:g> رکھیں۔"</string>
diff --git a/packages/PackageInstaller/res/values-uz/strings.xml b/packages/PackageInstaller/res/values-uz/strings.xml
index fc1b916..f3d16b5 100644
--- a/packages/PackageInstaller/res/values-uz/strings.xml
+++ b/packages/PackageInstaller/res/values-uz/strings.xml
@@ -56,6 +56,7 @@
     <string name="uninstall_application_text" msgid="3816830743706143980">"Bu ilovani o‘chirib tashlamoqchimisiz?"</string>
     <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Ushbu ilova "<b>"barcha"</b>" foydalanuvchilar uchun o‘chirilsinmi? Ilova va uning axborotlari qurilmadagi "<b>"barcha"</b>" foydalanuvchilardan o‘chib ketadi."</string>
     <string name="uninstall_application_text_user" msgid="498072714173920526">"Haqiqatdan ham <xliff:g id="USERNAME">%1$s</xliff:g> foydalanuvchi uchun ushbu ilovani olib tashlamoqchimisiz?"</string>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Bu ilova ish profilidan olib tashlansinmi?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"Bu ilova boshlang‘ich versiyasi bilan almashtirilsinmi? Barcha axborotlar o‘chirib tashlanadi."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Bu ilova boshlang‘ich versiyasi bilan almashtirilsinmi? Barcha axborotlar o‘chirib tashlanadi. Bu qurilmaning barcha foydalanuvchilariga, jumladan, ularning ishchi profillariga ham ta’sir qiladi."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"<xliff:g id="SIZE">%1$s</xliff:g> hajmdagi ilova axborotlari saqlab qolinsin"</string>
diff --git a/packages/PackageInstaller/res/values-vi/strings.xml b/packages/PackageInstaller/res/values-vi/strings.xml
index 03b381b..eacbe1d 100644
--- a/packages/PackageInstaller/res/values-vi/strings.xml
+++ b/packages/PackageInstaller/res/values-vi/strings.xml
@@ -56,6 +56,7 @@
     <string name="uninstall_application_text" msgid="3816830743706143980">"Bạn có muốn gỡ cài đặt ứng dụng này không?"</string>
     <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Bạn có muốn gỡ cài đặt ứng dụng này cho "<b>"tất cả"</b>" người dùng không? Ứng dụng và dữ liệu của ứng dụng sẽ bị xóa khỏi "<b>"tất cả"</b>" người dùng trên thiết bị."</string>
     <string name="uninstall_application_text_user" msgid="498072714173920526">"Bạn có muốn gỡ cài đặt ứng dụng này cho người dùng <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Bạn có muốn gỡ cài đặt ứng dụng này khỏi hồ sơ công việc của mình không?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"Thay thế ứng dụng này bằng phiên bản gốc? Tất cả dữ liệu sẽ bị xóa."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Thay thế ứng dụng này bằng phiên bản gốc? Tất cả dữ liệu sẽ bị xóa. Điều này ảnh hưởng đến tất cả người dùng thiết bị này, bao gồm cả những người có hồ sơ công việc."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"Giữ lại <xliff:g id="SIZE">%1$s</xliff:g> dữ liệu ứng dụng."</string>
diff --git a/packages/PackageInstaller/res/values-zh-rCN/strings.xml b/packages/PackageInstaller/res/values-zh-rCN/strings.xml
index e53dd46..924397f 100644
--- a/packages/PackageInstaller/res/values-zh-rCN/strings.xml
+++ b/packages/PackageInstaller/res/values-zh-rCN/strings.xml
@@ -56,6 +56,7 @@
     <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>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"您想从您的工作资料中卸载此应用吗?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"要将此应用替换为出厂版本吗?这样会移除所有数据。"</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"要将此应用替换为出厂版本吗?这样会移除所有数据,并会影响此设备的所有用户(包括已设置工作资料的用户)。"</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"保留 <xliff:g id="SIZE">%1$s</xliff:g> 的应用数据。"</string>
diff --git a/packages/PackageInstaller/res/values-zh-rHK/strings.xml b/packages/PackageInstaller/res/values-zh-rHK/strings.xml
index 1d00963..dce8cfe 100644
--- a/packages/PackageInstaller/res/values-zh-rHK/strings.xml
+++ b/packages/PackageInstaller/res/values-zh-rHK/strings.xml
@@ -56,6 +56,7 @@
     <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>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"要從工作設定檔解除安裝此應用程式嗎?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"要將此應用程式回復至原廠版本嗎?系統會移除所有資料。"</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"要將此應用程式回復至原廠版本嗎?系統會移除所有資料。此裝置的所有使用者 (包括使用工作設定檔的使用者) 亦會受影響。"</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"保留應用程式資料 (<xliff:g id="SIZE">%1$s</xliff:g>)。"</string>
diff --git a/packages/PackageInstaller/res/values-zh-rTW/strings.xml b/packages/PackageInstaller/res/values-zh-rTW/strings.xml
index e54e351..383802e 100644
--- a/packages/PackageInstaller/res/values-zh-rTW/strings.xml
+++ b/packages/PackageInstaller/res/values-zh-rTW/strings.xml
@@ -56,6 +56,7 @@
     <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>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"要從工作資料夾解除安裝這個應用程式嗎?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"要將應用程式換成原廠版本嗎?這麼做會移除所有資料。"</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"要將應用程式換成原廠版本嗎?這麼做會移除所有資料。凡是這個裝置的使用者 (包括設置工作資料夾的使用者),皆會受到影響。"</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"保留 <xliff:g id="SIZE">%1$s</xliff:g> 的應用程式資料。"</string>
diff --git a/packages/PackageInstaller/res/values-zu/strings.xml b/packages/PackageInstaller/res/values-zu/strings.xml
index c61b980..ef88552 100644
--- a/packages/PackageInstaller/res/values-zu/strings.xml
+++ b/packages/PackageInstaller/res/values-zu/strings.xml
@@ -56,6 +56,7 @@
     <string name="uninstall_application_text" msgid="3816830743706143980">"Ufuna ukukhipha le app?"</string>
     <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Ingabe ufuna ukukhipha lolu hlelo lokusebenza kubo "<b>"bonke"</b>" abasebenzisi? Uhlelo lokusebenza nedatha yalo kuzosuswa kubo "<b>"bonke"</b>" abasebenzisi kudivayisi."</string>
     <string name="uninstall_application_text_user" msgid="498072714173920526">"Ingabe ufuna ukukhiphela lolu hlelo lokusebenza kumsebenzisi ongu-<xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Ingabe ufuna ukukhipha le app kusukela kuphrofayela yakho yokusebenza?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"Shintshanisa lolu hlelo lokusebenza ngenguqulo yasekuqaleni? Yonke idatha izosuswa."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Shintshanisa lolu hlelo lokusebenza ngenguqulo yasekuqaleni? Yonke idatha izosuswa. Lokhu kuthinta bonke abasebenzisi bale divayisi, abafaka labo abanamaphrofayela wokusebenza."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"Gcina u-<xliff:g id="SIZE">%1$s</xliff:g> wedatha yohlelo lokusebenza."</string>
@@ -87,7 +88,7 @@
     <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Ithebulethi yakho nedatha yomuntu siqu zisengcupheni kakhulu ekuhlaselweni izinhlelo zokusebenza ezingaziwa. Ngokufaka lolu hlelo lokusebenza, uyavuma ukuthi unesibopho sanoma ikuphi ukonakala kuthebulethi yakho noma ukulahleka kwedatha okungabangelwa ukusetshenziswa kwayo."</string>
     <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"Idatha yakho ye-TV neyomuntu siqu isengcupheni kakhulu ekuhlaselweni izinhlelo zokusebenza ezingaziwa. Ngokufaka lolu hlelo lokusebenza, uyavuma ukuthi unesibopho sanoma ikuphi ukonakala ku-TV yakho noma ukulahlekelwa kwedatha okungabangelwa ukusetshenziswa kwayo."</string>
     <string name="anonymous_source_continue" msgid="4375745439457209366">"Qhubeka"</string>
-    <string name="external_sources_settings" msgid="4046964413071713807">"Izilungiselelo"</string>
+    <string name="external_sources_settings" msgid="4046964413071713807">"Amasethingi"</string>
     <string name="wear_app_channel" msgid="1960809674709107850">"Ifaka/ikhipha izinhlelo zokusebenza ze-wear"</string>
     <string name="app_installed_notification_channel_description" msgid="2695385797601574123">"Isaziso sokufakwa kohlelo lokusebenza"</string>
     <string name="notification_installation_success_message" msgid="6450467996056038442">"Ifakwe ngempumelelo"</string>
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/wear/PackageInstallerImpl.java b/packages/PackageInstaller/src/com/android/packageinstaller/wear/PackageInstallerImpl.java
index 7e0490a..063d789 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/wear/PackageInstallerImpl.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/wear/PackageInstallerImpl.java
@@ -264,7 +264,8 @@
         String action = ACTION_INSTALL_COMMIT + "." + packageName;
         IntentFilter intentFilter = new IntentFilter();
         intentFilter.addAction(action);
-        mContext.registerReceiver(broadcastReceiver, intentFilter);
+        mContext.registerReceiver(broadcastReceiver, intentFilter,
+                Context.RECEIVER_EXPORTED_UNAUDITED);
 
         // Create a matching PendingIntent and use it to generate the IntentSender
         Intent broadcastIntent = new Intent(action);
diff --git a/packages/PrintSpooler/res/values-te/strings.xml b/packages/PrintSpooler/res/values-te/strings.xml
index 50e6f3b..a1ed2ca 100644
--- a/packages/PrintSpooler/res/values-te/strings.xml
+++ b/packages/PrintSpooler/res/values-te/strings.xml
@@ -31,8 +31,8 @@
     <string name="template_all_pages" msgid="3322235982020148762">"మొత్తం <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
     <string name="template_page_range" msgid="428638530038286328">"<xliff:g id="PAGE_COUNT">%1$s</xliff:g> పరిధి"</string>
     <string name="pages_range_example" msgid="8558694453556945172">"ఉదా. 1—5,8,11—13"</string>
-    <string name="print_preview" msgid="8010217796057763343">"ముద్రణ పరిదృశ్యం"</string>
-    <string name="install_for_print_preview" msgid="6366303997385509332">"పరిదృశ్యం చేయడానికి PDF వ్యూయర్‌ను ఇన్‌స్టాల్ చేయండి"</string>
+    <string name="print_preview" msgid="8010217796057763343">"ముద్రణ ప్రివ్యూ"</string>
+    <string name="install_for_print_preview" msgid="6366303997385509332">"ప్రివ్యూ చేయడానికి PDF వ్యూయర్‌ను ఇన్‌స్టాల్ చేయండి"</string>
     <string name="printing_app_crashed" msgid="854477616686566398">"ముద్రణ యాప్ క్రాష్ అయ్యింది"</string>
     <string name="generating_print_job" msgid="3119608742651698916">"ముద్రణ జాబ్‌ను ఉత్పన్నం చేస్తోంది"</string>
     <string name="save_as_pdf" msgid="5718454119847596853">"PDF వలె సేవ్ చేయి"</string>
@@ -106,6 +106,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"క్షమించండి, అది పని చేయలేదు. మళ్లీ ప్రయత్నించండి."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"మళ్లీ ప్రయత్నించు"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"ఈ ప్రింటర్ ప్రస్తుతం అందుబాటులో లేదు."</string>
-    <string name="print_cannot_load_page" msgid="6179560924492912009">"పరిదృశ్యాన్ని ప్రదర్శించడం సాధ్యపడలేదు"</string>
-    <string name="print_preparing_preview" msgid="3939930735671364712">"పరిదృశ్యం సిద్ధమవుతోంది…"</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"ప్రివ్యూను ప్రదర్శించడం సాధ్యపడలేదు"</string>
+    <string name="print_preparing_preview" msgid="3939930735671364712">"ప్రివ్యూ సిద్ధమవుతోంది…"</string>
 </resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/src/com/android/settingslib/widget/BannerMessagePreference.java b/packages/SettingsLib/BannerMessagePreference/src/com/android/settingslib/widget/BannerMessagePreference.java
index 3a70d65..afeb24a 100644
--- a/packages/SettingsLib/BannerMessagePreference/src/com/android/settingslib/widget/BannerMessagePreference.java
+++ b/packages/SettingsLib/BannerMessagePreference/src/com/android/settingslib/widget/BannerMessagePreference.java
@@ -152,10 +152,22 @@
         mPositiveButtonInfo.mButton = (Button) holder.findViewById(R.id.banner_positive_btn);
         mNegativeButtonInfo.mButton = (Button) holder.findViewById(R.id.banner_negative_btn);
 
+        final Resources.Theme theme = context.getTheme();
+        @ColorInt final int accentColor =
+                context.getResources().getColor(mAttentionLevel.getAccentColorResId(), theme);
+
+        final ImageView iconView = (ImageView) holder.findViewById(R.id.banner_icon);
+        if (iconView != null) {
+            Drawable icon = getIcon();
+            iconView.setImageDrawable(
+                    icon == null
+                            ? getContext().getDrawable(R.drawable.ic_warning)
+                            : icon);
+            iconView.setColorFilter(
+                    new PorterDuffColorFilter(accentColor, PorterDuff.Mode.SRC_IN));
+        }
+
         if (IS_AT_LEAST_S) {
-            final Resources.Theme theme = context.getTheme();
-            @ColorInt final int accentColor =
-                    context.getResources().getColor(mAttentionLevel.getAccentColorResId(), theme);
             @ColorInt final int backgroundColor =
                     context.getResources().getColor(
                             mAttentionLevel.getBackgroundColorResId(), theme);
@@ -174,16 +186,6 @@
             subtitleView.setText(mSubtitle);
             subtitleView.setVisibility(mSubtitle == null ? View.GONE : View.VISIBLE);
 
-            final ImageView iconView = (ImageView) holder.findViewById(R.id.banner_icon);
-            if (iconView != null) {
-                Drawable icon = getIcon();
-                iconView.setImageDrawable(
-                        icon == null
-                                ? getContext().getDrawable(R.drawable.ic_warning)
-                                : icon);
-                iconView.setColorFilter(
-                        new PorterDuffColorFilter(accentColor, PorterDuff.Mode.SRC_IN));
-            }
         } else {
             holder.setDividerAllowedAbove(true);
             holder.setDividerAllowedBelow(true);
@@ -323,7 +325,6 @@
     /**
      * Sets the attention level. This will update the color theme of the preference.
      */
-    @RequiresApi(Build.VERSION_CODES.S)
     public BannerMessagePreference setAttentionLevel(AttentionLevel attentionLevel) {
         if (attentionLevel == mAttentionLevel) {
             return this;
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/BasePreferencesFragment.java b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/BasePreferencesFragment.java
new file mode 100644
index 0000000..8ebbac3
--- /dev/null
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/BasePreferencesFragment.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.settingslib.collapsingtoolbar;
+
+import androidx.fragment.app.FragmentActivity;
+import androidx.preference.PreferenceFragmentCompat;
+
+import com.android.settingslib.utils.BuildCompatUtils;
+
+import com.google.android.material.appbar.AppBarLayout;
+
+/**
+ * A base fragment that supports multi-fragments in one activity. The activity likes to switch the
+ * different fragments which extend this base fragment and must use the following code to add the
+ * fragment to stack.
+ *
+ * protected void onCreate(Bundle savedState) {
+ *    // omitted…
+ *    getFragmentManager()
+ *            .beginTransaction()
+ *            .add(R.id.content_frame, new Your_Fragment())
+ *            // Add root page to back-history
+ *            .addToBackStack( null)
+ *            .commit();
+ *    // omitted
+ * }
+ */
+public abstract class BasePreferencesFragment extends PreferenceFragmentCompat {
+
+    /**
+     * Gets the title which the fragment likes to show on app bar. The child class must implement
+     * this
+     * function.
+     *
+     * @return The title of the fragment will show on app bar.
+     */
+    public abstract CharSequence getTitle();
+
+    @Override
+    public void onResume() {
+        super.onResume();
+
+        FragmentActivity activity = getActivity();
+        if (activity != null) {
+            activity.setTitle(getTitle());
+
+            if (BuildCompatUtils.isAtLeastS()) {
+                AppBarLayout appBarLayout = (AppBarLayout) activity.findViewById(R.id.app_bar);
+
+                if (appBarLayout != null) {
+                    appBarLayout.setExpanded(/* expanded= */ true);
+                }
+            }
+        }
+    }
+}
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseActivity.java b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseActivity.java
index 84a6b36..543a5a0 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseActivity.java
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseActivity.java
@@ -23,16 +23,13 @@
 import android.view.ViewGroup;
 import android.widget.Toolbar;
 
-import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
-import androidx.coordinatorlayout.widget.CoordinatorLayout;
 import androidx.fragment.app.FragmentActivity;
 
 import com.android.settingslib.utils.BuildCompatUtils;
 
 import com.google.android.material.appbar.AppBarLayout;
 import com.google.android.material.appbar.CollapsingToolbarLayout;
-import com.google.android.material.resources.TextAppearanceConfig;
 
 /**
  * A base Activity that has a collapsing toolbar layout is used for the activities intending to
@@ -40,12 +37,22 @@
  */
 public class CollapsingToolbarBaseActivity extends FragmentActivity {
 
-    private static final float TOOLBAR_LINE_SPACING_MULTIPLIER = 1.1f;
+    private class DelegateCallback implements CollapsingToolbarDelegate.HostCallback {
+        @Nullable
+        @Override
+        public ActionBar setActionBar(Toolbar toolbar) {
+            CollapsingToolbarBaseActivity.super.setActionBar(toolbar);
+            return CollapsingToolbarBaseActivity.super.getActionBar();
+        }
 
-    @Nullable
-    private CollapsingToolbarLayout mCollapsingToolbarLayout;
-    @Nullable
-    private AppBarLayout mAppBarLayout;
+        @Override
+        public void setOuterTitle(CharSequence title) {
+            CollapsingToolbarBaseActivity.super.setTitle(title);
+        }
+    }
+
+    private CollapsingToolbarDelegate mToolbardelegate;
+
     private int mCustomizeLayoutResId = 0;
 
     @Override
@@ -55,31 +62,16 @@
             super.setContentView(mCustomizeLayoutResId);
             return;
         }
-        // Force loading font synchronously for collapsing toolbar layout
-        TextAppearanceConfig.setShouldLoadFontSynchronously(true);
-        super.setContentView(R.layout.collapsing_toolbar_base_layout);
-        mCollapsingToolbarLayout = findViewById(R.id.collapsing_toolbar);
-        mAppBarLayout = findViewById(R.id.app_bar);
-        if (mCollapsingToolbarLayout != null) {
-            mCollapsingToolbarLayout.setLineSpacingMultiplier(TOOLBAR_LINE_SPACING_MULTIPLIER);
-        }
-        disableCollapsingToolbarLayoutScrollingBehavior();
 
-        final Toolbar toolbar = findViewById(R.id.action_bar);
-        setActionBar(toolbar);
-
-        // Enable title and home button by default
-        final ActionBar actionBar = getActionBar();
-        if (actionBar != null) {
-            actionBar.setDisplayHomeAsUpEnabled(true);
-            actionBar.setHomeButtonEnabled(true);
-            actionBar.setDisplayShowTitleEnabled(true);
-        }
+        mToolbardelegate = new CollapsingToolbarDelegate(new DelegateCallback());
+        View view = mToolbardelegate.onCreateView(getLayoutInflater(), null);
+        super.setContentView(view);
     }
 
     @Override
     public void setContentView(int layoutResID) {
-        final ViewGroup parent = findViewById(R.id.content_frame);
+        final ViewGroup parent = (mToolbardelegate == null) ? findViewById(R.id.content_frame)
+                : mToolbardelegate.getContentFrameLayout();
         if (parent != null) {
             parent.removeAllViews();
         }
@@ -88,7 +80,8 @@
 
     @Override
     public void setContentView(View view) {
-        final ViewGroup parent = findViewById(R.id.content_frame);
+        final ViewGroup parent = (mToolbardelegate == null) ? findViewById(R.id.content_frame)
+                : mToolbardelegate.getContentFrameLayout();
         if (parent != null) {
             parent.addView(view);
         }
@@ -96,7 +89,8 @@
 
     @Override
     public void setContentView(View view, ViewGroup.LayoutParams params) {
-        final ViewGroup parent = findViewById(R.id.content_frame);
+        final ViewGroup parent = (mToolbardelegate == null) ? findViewById(R.id.content_frame)
+                : mToolbardelegate.getContentFrameLayout();
         if (parent != null) {
             parent.addView(view, params);
         }
@@ -113,20 +107,12 @@
 
     @Override
     public void setTitle(CharSequence title) {
-        if (mCollapsingToolbarLayout != null) {
-            mCollapsingToolbarLayout.setTitle(title);
-        } else {
-            super.setTitle(title);
-        }
+        mToolbardelegate.setTitle(title);
     }
 
     @Override
     public void setTitle(int titleId) {
-        if (mCollapsingToolbarLayout != null) {
-            mCollapsingToolbarLayout.setTitle(getText(titleId));
-        } else {
-            super.setTitle(titleId);
-        }
+        setTitle(getText(titleId));
     }
 
     @Override
@@ -142,7 +128,7 @@
      */
     @Nullable
     public CollapsingToolbarLayout getCollapsingToolbarLayout() {
-        return mCollapsingToolbarLayout;
+        return mToolbardelegate.getCollapsingToolbarLayout();
     }
 
     /**
@@ -150,23 +136,6 @@
      */
     @Nullable
     public AppBarLayout getAppBarLayout() {
-        return mAppBarLayout;
-    }
-
-    private void disableCollapsingToolbarLayoutScrollingBehavior() {
-        if (mAppBarLayout == null) {
-            return;
-        }
-        final CoordinatorLayout.LayoutParams params =
-                (CoordinatorLayout.LayoutParams) mAppBarLayout.getLayoutParams();
-        final AppBarLayout.Behavior behavior = new AppBarLayout.Behavior();
-        behavior.setDragCallback(
-                new AppBarLayout.Behavior.DragCallback() {
-                    @Override
-                    public boolean canDrag(@NonNull AppBarLayout appBarLayout) {
-                        return false;
-                    }
-                });
-        params.setBehavior(behavior);
+        return mToolbardelegate.getAppBarLayout();
     }
 }
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseFragment.java b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseFragment.java
index eb8b59e..b605074 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseFragment.java
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseFragment.java
@@ -16,7 +16,8 @@
 
 package com.android.settingslib.collapsingtoolbar;
 
-import android.os.Build;
+import android.app.ActionBar;
+import android.content.Context;
 import android.os.Bundle;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -37,44 +38,33 @@
  */
 public abstract class CollapsingToolbarBaseFragment extends Fragment {
 
-    private static final float TOOLBAR_LINE_SPACING_MULTIPLIER = 1.1f;
+    private class DelegateCallback implements CollapsingToolbarDelegate.HostCallback {
+        @Nullable
+        @Override
+        public ActionBar setActionBar(Toolbar toolbar) {
+            requireActivity().setActionBar(toolbar);
+            return null;
+        }
 
-    @Nullable
-    private CoordinatorLayout mCoordinatorLayout;
-    @Nullable
-    private CollapsingToolbarLayout mCollapsingToolbarLayout;
-    @Nullable
-    private AppBarLayout mAppBarLayout;
-    @NonNull
-    private Toolbar mToolbar;
-    @NonNull
-    private FrameLayout mContentFrameLayout;
+        @Override
+        public void setOuterTitle(CharSequence title) {
+            // ignore
+        }
+    }
+
+    private CollapsingToolbarDelegate mToolbardelegate;
+
+    @Override
+    public void onAttach(Context context) {
+        super.onAttach(context);
+        mToolbardelegate = new CollapsingToolbarDelegate(new DelegateCallback());
+    }
 
     @Nullable
     @Override
     public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
             @Nullable Bundle savedInstanceState) {
-        final View view = inflater.inflate(R.layout.collapsing_toolbar_base_layout, container,
-                false);
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
-            mCoordinatorLayout = view.findViewById(R.id.content_parent);
-        }
-        mCollapsingToolbarLayout = view.findViewById(R.id.collapsing_toolbar);
-        mAppBarLayout = view.findViewById(R.id.app_bar);
-        if (mCollapsingToolbarLayout != null) {
-            mCollapsingToolbarLayout.setLineSpacingMultiplier(TOOLBAR_LINE_SPACING_MULTIPLIER);
-        }
-        disableCollapsingToolbarLayoutScrollingBehavior();
-        mToolbar = view.findViewById(R.id.action_bar);
-        mContentFrameLayout = view.findViewById(R.id.content_frame);
-        return view;
-    }
-
-    @Override
-    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
-        super.onActivityCreated(savedInstanceState);
-
-        requireActivity().setActionBar(mToolbar);
+        return mToolbardelegate.onCreateView(inflater, container);
     }
 
     /**
@@ -82,7 +72,7 @@
      */
     @Nullable
     public CoordinatorLayout getCoordinatorLayout() {
-        return mCoordinatorLayout;
+        return mToolbardelegate.getCoordinatorLayout();
     }
 
     /**
@@ -90,7 +80,7 @@
      */
     @Nullable
     public AppBarLayout getAppBarLayout() {
-        return mAppBarLayout;
+        return mToolbardelegate.getAppBarLayout();
     }
 
     /**
@@ -98,7 +88,7 @@
      */
     @Nullable
     public CollapsingToolbarLayout getCollapsingToolbarLayout() {
-        return mCollapsingToolbarLayout;
+        return mToolbardelegate.getCollapsingToolbarLayout();
     }
 
     /**
@@ -106,23 +96,6 @@
      */
     @NonNull
     public FrameLayout getContentFrameLayout() {
-        return mContentFrameLayout;
-    }
-
-    private void disableCollapsingToolbarLayoutScrollingBehavior() {
-        if (mAppBarLayout == null) {
-            return;
-        }
-        final CoordinatorLayout.LayoutParams params =
-                (CoordinatorLayout.LayoutParams) mAppBarLayout.getLayoutParams();
-        final AppBarLayout.Behavior behavior = new AppBarLayout.Behavior();
-        behavior.setDragCallback(
-                new AppBarLayout.Behavior.DragCallback() {
-                    @Override
-                    public boolean canDrag(@NonNull AppBarLayout appBarLayout) {
-                        return false;
-                    }
-                });
-        params.setBehavior(behavior);
+        return mToolbardelegate.getContentFrameLayout();
     }
 }
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarDelegate.java b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarDelegate.java
new file mode 100644
index 0000000..30e3973
--- /dev/null
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarDelegate.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.collapsingtoolbar;
+
+import android.app.ActionBar;
+import android.os.Build;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import android.widget.Toolbar;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.coordinatorlayout.widget.CoordinatorLayout;
+
+import com.google.android.material.appbar.AppBarLayout;
+import com.google.android.material.appbar.CollapsingToolbarLayout;
+
+/**
+ * A delegate that allows to use the collapsing toolbar layout in hosts that doesn't want/need to
+ * extend from {@link CollapsingToolbarBaseActivity} or from {@link CollapsingToolbarBaseFragment}.
+ */
+public class CollapsingToolbarDelegate {
+
+    /** Interface to be implemented by the host of the Collapsing Toolbar. */
+    public interface HostCallback {
+        /**
+         * Called when a Toolbar should be set on the host.
+         *
+         * <p>If the host wants action bar to be modified, it should return it.
+         */
+        @Nullable
+        ActionBar setActionBar(Toolbar toolbar);
+
+        /** Sets a title on the host. */
+        void setOuterTitle(CharSequence title);
+    }
+
+    private static final float TOOLBAR_LINE_SPACING_MULTIPLIER = 1.1f;
+
+    @Nullable
+    private CoordinatorLayout mCoordinatorLayout;
+    @Nullable
+    private CollapsingToolbarLayout mCollapsingToolbarLayout;
+    @Nullable
+    private AppBarLayout mAppBarLayout;
+    @NonNull
+    private Toolbar mToolbar;
+    @NonNull
+    private FrameLayout mContentFrameLayout;
+    @NonNull
+    private final HostCallback mHostCallback;
+
+    public CollapsingToolbarDelegate(@NonNull HostCallback hostCallback) {
+        mHostCallback = hostCallback;
+    }
+
+    /** Method to call that creates the root view of the collapsing toolbar. */
+    @SuppressWarnings("RestrictTo")
+    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container) {
+        final View view =
+                inflater.inflate(R.layout.collapsing_toolbar_base_layout, container, false);
+        if (view instanceof CoordinatorLayout) {
+            mCoordinatorLayout = (CoordinatorLayout) view;
+        }
+        mCollapsingToolbarLayout = view.findViewById(R.id.collapsing_toolbar);
+        mAppBarLayout = view.findViewById(R.id.app_bar);
+        if (mCollapsingToolbarLayout != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+            mCollapsingToolbarLayout.setLineSpacingMultiplier(TOOLBAR_LINE_SPACING_MULTIPLIER);
+        }
+        disableCollapsingToolbarLayoutScrollingBehavior();
+        mToolbar = view.findViewById(R.id.action_bar);
+        mContentFrameLayout = view.findViewById(R.id.content_frame);
+        final ActionBar actionBar = mHostCallback.setActionBar(mToolbar);
+
+        // Enable title and home button by default
+        if (actionBar != null) {
+            actionBar.setDisplayHomeAsUpEnabled(true);
+            actionBar.setHomeButtonEnabled(true);
+            actionBar.setDisplayShowTitleEnabled(true);
+        }
+        return view;
+    }
+
+    /** Return an instance of CoordinatorLayout. */
+    @Nullable
+    public CoordinatorLayout getCoordinatorLayout() {
+        return mCoordinatorLayout;
+    }
+
+    /** Sets the title on the collapsing layout, delegating to host if needed. */
+    public void setTitle(CharSequence title) {
+        if (mCollapsingToolbarLayout != null) {
+            mCollapsingToolbarLayout.setTitle(title);
+        } else {
+            mHostCallback.setOuterTitle(title);
+        }
+    }
+
+    /** Returns an instance of collapsing toolbar. */
+    @Nullable
+    public CollapsingToolbarLayout getCollapsingToolbarLayout() {
+        return mCollapsingToolbarLayout;
+    }
+
+    /** Return the content frame layout. */
+    @NonNull
+    public FrameLayout getContentFrameLayout() {
+        return mContentFrameLayout;
+    }
+
+    public Toolbar getToolbar() {
+        return mToolbar;
+    }
+
+    /** Return an instance of app bar. */
+    @Nullable
+    public AppBarLayout getAppBarLayout() {
+        return mAppBarLayout;
+    }
+
+    private void disableCollapsingToolbarLayoutScrollingBehavior() {
+        if (mAppBarLayout == null) {
+            return;
+        }
+        final CoordinatorLayout.LayoutParams params =
+                (CoordinatorLayout.LayoutParams) mAppBarLayout.getLayoutParams();
+        final AppBarLayout.Behavior behavior = new AppBarLayout.Behavior();
+        behavior.setDragCallback(
+                new AppBarLayout.Behavior.DragCallback() {
+                    @Override
+                    public boolean canDrag(@NonNull AppBarLayout appBarLayout) {
+                        return false;
+                    }
+                });
+        params.setBehavior(behavior);
+    }
+}
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/SettingsTransitionActivity.java b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/SettingsTransitionActivity.java
index 3a7fe3b..38afd44 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/SettingsTransitionActivity.java
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/SettingsTransitionActivity.java
@@ -23,7 +23,6 @@
  * Settings transition applied.
  */
 public abstract class SettingsTransitionActivity extends FragmentActivity {
-    private static final String TAG = "SettingsTransitionActivity";
 
     protected boolean isSettingsTransitionEnabled() {
         return false;
diff --git a/packages/SettingsLib/FooterPreference/res/layout-v31/preference_footer.xml b/packages/SettingsLib/FooterPreference/res/layout-v31/preference_footer.xml
index e586dbb..b127630 100644
--- a/packages/SettingsLib/FooterPreference/res/layout-v31/preference_footer.xml
+++ b/packages/SettingsLib/FooterPreference/res/layout-v31/preference_footer.xml
@@ -24,7 +24,6 @@
     android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
     android:background="?android:attr/selectableItemBackground"
     android:orientation="vertical"
-    android:importantForAccessibility = "no"
     android:clipToPadding="false">
 
     <LinearLayout
diff --git a/packages/SettingsLib/FooterPreference/res/layout/preference_footer.xml b/packages/SettingsLib/FooterPreference/res/layout/preference_footer.xml
index 990860a..23192b6 100644
--- a/packages/SettingsLib/FooterPreference/res/layout/preference_footer.xml
+++ b/packages/SettingsLib/FooterPreference/res/layout/preference_footer.xml
@@ -23,7 +23,6 @@
     android:paddingStart="?android:attr/listPreferredItemPaddingStart"
     android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
     android:background="?android:attr/selectableItemBackground"
-    android:importantForAccessibility = "no"
     android:clipToPadding="false">
 
     <LinearLayout
diff --git a/packages/SettingsLib/FooterPreference/src/com/android/settingslib/widget/FooterPreference.java b/packages/SettingsLib/FooterPreference/src/com/android/settingslib/widget/FooterPreference.java
index fe7988f..e51bb45 100644
--- a/packages/SettingsLib/FooterPreference/src/com/android/settingslib/widget/FooterPreference.java
+++ b/packages/SettingsLib/FooterPreference/src/com/android/settingslib/widget/FooterPreference.java
@@ -61,6 +61,7 @@
         title.setMovementMethod(new LinkMovementMethod());
         title.setClickable(false);
         title.setLongClickable(false);
+        title.setFocusable(false);
         if (!TextUtils.isEmpty(mContentDescription)) {
             title.setContentDescription(mContentDescription);
         }
@@ -79,6 +80,7 @@
             if (!TextUtils.isEmpty(mLearnMoreContentDescription)) {
                 learnMore.setContentDescription(mLearnMoreContentDescription);
             }
+            learnMore.setFocusable(false);
         } else {
             learnMore.setVisibility(View.GONE);
         }
diff --git a/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_ic_info.xml b/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_ic_info.xml
new file mode 100644
index 0000000..c8037c8
--- /dev/null
+++ b/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_ic_info.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.
+-->
+<!-- copy from frameworks/base/core/res/res/drawable/ic_info.xml-->
+<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="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z"/>
+</vector>
\ No newline at end of file
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 d0c2d0b..59ae122 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/layout/settingslib_main_switch_bar.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/layout/settingslib_main_switch_bar.xml
@@ -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="@drawable/settingslib_ic_info"
         android:visibility="gone"/>
 
     <Switch
@@ -51,6 +51,8 @@
         android:layout_height="wrap_content"
         android:layout_gravity="center_vertical"
         android:layout_marginEnd="@dimen/settingslib_switchbar_subsettings_margin_end"
+        android:focusable="false"
+        android:clickable="false"
         android:theme="@style/SwitchBar.Switch.Settingslib"/>
 </LinearLayout>
 
diff --git a/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java b/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java
index 6d5615d..383bf8e 100644
--- a/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java
+++ b/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java
@@ -30,6 +30,7 @@
 import android.widget.TextView;
 
 import androidx.annotation.ColorInt;
+import androidx.annotation.Nullable;
 
 import com.android.settingslib.utils.BuildCompatUtils;
 
@@ -97,6 +98,10 @@
         }
         addOnSwitchChangeListener((switchView, isChecked) -> setChecked(isChecked));
 
+        if (mSwitch.getVisibility() == VISIBLE) {
+            mSwitch.setOnCheckedChangeListener(this);
+        }
+
         setChecked(mSwitch.isChecked());
 
         if (attrs != null) {
@@ -118,6 +123,12 @@
     }
 
     @Override
+    public void setOnClickListener(@Nullable OnClickListener l) {
+        super.setOnClickListener(l);
+        mSwitch.setOnClickListener(l);
+    }
+
+    @Override
     public boolean performClick() {
         return mSwitch.performClick();
     }
diff --git a/packages/SettingsLib/SearchWidget/res/values-sv/strings.xml b/packages/SettingsLib/SearchWidget/res/values-sv/strings.xml
index 96e0b4e..0dbc0ea 100644
--- a/packages/SettingsLib/SearchWidget/res/values-sv/strings.xml
+++ b/packages/SettingsLib/SearchWidget/res/values-sv/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">"Sökinställningar"</string>
+    <string name="search_menu" msgid="1914043873178389845">"Sök i inställningar"</string>
 </resources>
diff --git a/packages/SettingsLib/UsageProgressBarPreference/src/com/android/settingslib/widget/UsageProgressBarPreference.java b/packages/SettingsLib/UsageProgressBarPreference/src/com/android/settingslib/widget/UsageProgressBarPreference.java
index 8e010fa..4eedab2 100644
--- a/packages/SettingsLib/UsageProgressBarPreference/src/com/android/settingslib/widget/UsageProgressBarPreference.java
+++ b/packages/SettingsLib/UsageProgressBarPreference/src/com/android/settingslib/widget/UsageProgressBarPreference.java
@@ -40,7 +40,7 @@
  */
 public class UsageProgressBarPreference extends Preference {
 
-    private final Pattern mNumberPattern = Pattern.compile("[\\d]*[\\.,]?[\\d]+");
+    private final Pattern mNumberPattern = Pattern.compile("[\\d]*[\\٫.,]?[\\d]+");
 
     private CharSequence mUsageSummary;
     private CharSequence mTotalSummary;
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 662ffdd..6357f3c 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -492,7 +492,7 @@
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"جارٍ الشحن لاسلكيًا"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"لا يتم الشحن"</string>
     <string name="battery_info_status_not_charging" msgid="3371084153747234837">"الجهاز متصل بالشاحن، ولا يتم الشحن."</string>
-    <string name="battery_info_status_full" msgid="1339002294876531312">"تم الشحن"</string>
+    <string name="battery_info_status_full" msgid="1339002294876531312">"مشحونة"</string>
     <string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"إعدادات يتحكم فيها المشرف"</string>
     <string name="disabled" msgid="8017887509554714950">"غير مفعّل"</string>
     <string name="external_source_trusted" msgid="1146522036773132905">"مسموح به"</string>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index a816f49..d90c08a 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -612,7 +612,7 @@
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"सुरू करा"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"बंद करा"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"वाहक नेटवर्क बदलत आहे"</string>
-    <string name="data_connection_3g" msgid="931852552688157407">"३G"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
     <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
     <string name="data_connection_cdma" msgid="9098161966701934334">"१X"</string>
     <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
diff --git a/packages/SettingsLib/res/values/dimens.xml b/packages/SettingsLib/res/values/dimens.xml
index c439cf0..9bccc3f 100644
--- a/packages/SettingsLib/res/values/dimens.xml
+++ b/packages/SettingsLib/res/values/dimens.xml
@@ -22,7 +22,7 @@
     <!-- The translation for disappearing security views after having solved them. -->
     <dimen name="disappear_y_translation">-32dp</dimen>
 
-    <dimen name="circle_avatar_size">40dp</dimen>
+    <dimen name="circle_avatar_size">190dp</dimen>
 
     <!-- Height of a user icon view -->
     <dimen name="user_icon_view_height">24dp</dimen>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 8e20e02..47b0744 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -1334,7 +1334,7 @@
     <string name="notice_header" translatable="false"></string>
 
     <!-- Name of the phone device. [CHAR LIMIT=30] -->
-    <string name="media_transfer_this_device_name">Phone speaker</string>
+    <string name="media_transfer_this_device_name">This phone</string>
     <!-- Name of the phone device with an active remote session. [CHAR LIMIT=30] -->
     <string name="media_transfer_this_phone">This phone</string>
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index a901160..290055c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -21,7 +21,6 @@
 import android.bluetooth.BluetoothCsipSetCoordinator;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothHearingAid;
-import android.bluetooth.BluetoothLeAudio;
 import android.bluetooth.BluetoothProfile;
 import android.bluetooth.BluetoothUuid;
 import android.content.Context;
@@ -1131,9 +1130,18 @@
     }
 
     /**
-     * @return resource for android auto string that describes the connection state of this device.
+     * See {@link #getCarConnectionSummary(boolean)}
      */
     public String getCarConnectionSummary() {
+        return getCarConnectionSummary(false);
+    }
+
+    /**
+     * Returns android auto string that describes the connection state of this device.
+     *
+     * @param shortSummary {@code true} if need to return short version summary
+     */
+    public String getCarConnectionSummary(boolean shortSummary) {
         boolean profileConnected = false;       // at least one profile is connected
         boolean a2dpNotConnected = false;       // A2DP is preferred but not connected
         boolean hfpNotConnected = false;        // HFP is preferred but not connected
@@ -1151,6 +1159,10 @@
                                 BluetoothUtils.getConnectionStateSummary(connectionStatus));
 
                     case BluetoothProfile.STATE_CONNECTED:
+                        if (shortSummary) {
+                            return mContext.getString(BluetoothUtils.getConnectionStateSummary(
+                                    connectionStatus), /* formatArgs= */ "");
+                        }
                         profileConnected = true;
                         break;
 
@@ -1248,7 +1260,8 @@
         }
 
         return getBondState() == BluetoothDevice.BOND_BONDING ?
-                mContext.getString(R.string.bluetooth_pairing) : null;
+                mContext.getString(R.string.bluetooth_pairing) :
+                mContext.getString(R.string.bluetooth_disconnected);
     }
 
     /**
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
index bbf0a02..4da47fd 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
@@ -38,6 +38,8 @@
     public static final String CATEGORY_SECURITY = "com.android.settings.category.ia.security";
     public static final String CATEGORY_SECURITY_LOCKSCREEN =
             "com.android.settings.category.ia.lockscreen";
+    public static final String CATEGORY_SECURITY_ADVANCED_SETTINGS =
+            "com.android.settings.category.ia.advanced_security";
     public static final String CATEGORY_ACCOUNT = "com.android.settings.category.ia.accounts";
     public static final String CATEGORY_ACCOUNT_DETAIL =
             "com.android.settings.category.ia.account_detail";
diff --git a/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java b/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java
index ab7b54d..6b9b750 100644
--- a/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java
+++ b/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java
@@ -17,9 +17,11 @@
 package com.android.settingslib.dream;
 
 import android.annotation.IntDef;
+import android.annotation.Nullable;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
@@ -57,6 +59,8 @@
         public boolean isActive;
         public ComponentName componentName;
         public ComponentName settingsComponentName;
+        public CharSequence description;
+        public Drawable previewImage;
 
         @Override
         public String toString() {
@@ -118,23 +122,47 @@
                 PackageManager.GET_META_DATA);
         List<DreamInfo> dreamInfos = new ArrayList<>(resolveInfos.size());
         for (ResolveInfo resolveInfo : resolveInfos) {
-            if (resolveInfo.serviceInfo == null)
+            if (resolveInfo.serviceInfo == null) {
                 continue;
+            }
             DreamInfo dreamInfo = new DreamInfo();
             dreamInfo.caption = resolveInfo.loadLabel(pm);
             dreamInfo.icon = resolveInfo.loadIcon(pm);
+            dreamInfo.description = getDescription(resolveInfo, pm);
             dreamInfo.componentName = getDreamComponentName(resolveInfo);
             dreamInfo.isActive = dreamInfo.componentName.equals(activeDream);
-            dreamInfo.settingsComponentName = getSettingsComponentName(pm, resolveInfo);
+
+            final DreamMetadata dreamMetadata = getDreamMetadata(pm, resolveInfo);
+            if (dreamMetadata != null) {
+                dreamInfo.settingsComponentName = dreamMetadata.mSettingsActivity;
+                dreamInfo.previewImage = dreamMetadata.mPreviewImage;
+            }
+
             dreamInfos.add(dreamInfo);
         }
         Collections.sort(dreamInfos, mComparator);
         return dreamInfos;
     }
 
+    private static CharSequence getDescription(ResolveInfo resolveInfo, PackageManager pm) {
+        String packageName = resolveInfo.resolvePackageName;
+        ApplicationInfo applicationInfo = null;
+        if (packageName == null) {
+            packageName = resolveInfo.serviceInfo.packageName;
+            applicationInfo = resolveInfo.serviceInfo.applicationInfo;
+        }
+        if (resolveInfo.serviceInfo.descriptionRes != 0) {
+            return pm.getText(packageName,
+                    resolveInfo.serviceInfo.descriptionRes,
+                    applicationInfo);
+        }
+        return null;
+    }
+
     public ComponentName getDefaultDream() {
-        if (mDreamManager == null)
+        if (mDreamManager == null) {
             return null;
+        }
         try {
             return mDreamManager.getDefaultDreamComponentForUser(mContext.getUserId());
         } catch (RemoteException e) {
@@ -306,57 +334,77 @@
     }
 
     private static ComponentName getDreamComponentName(ResolveInfo resolveInfo) {
-        if (resolveInfo == null || resolveInfo.serviceInfo == null)
+        if (resolveInfo == null || resolveInfo.serviceInfo == null) {
             return null;
+        }
         return new ComponentName(resolveInfo.serviceInfo.packageName, resolveInfo.serviceInfo.name);
     }
 
-    private static ComponentName getSettingsComponentName(PackageManager pm, ResolveInfo resolveInfo) {
-        if (resolveInfo == null
-                || resolveInfo.serviceInfo == null
-                || resolveInfo.serviceInfo.metaData == null)
+    private static final class DreamMetadata {
+        @Nullable
+        Drawable mPreviewImage;
+        @Nullable
+        ComponentName mSettingsActivity;
+    }
+
+    @Nullable
+    private static TypedArray readMetadata(PackageManager pm, ServiceInfo serviceInfo) {
+        if (serviceInfo == null || serviceInfo.metaData == null) {
             return null;
-        String cn = null;
-        XmlResourceParser parser = null;
-        Exception caughtException = null;
-        try {
-            parser = resolveInfo.serviceInfo.loadXmlMetaData(pm, DreamService.DREAM_META_DATA);
+        }
+        try (XmlResourceParser parser =
+                     serviceInfo.loadXmlMetaData(pm, DreamService.DREAM_META_DATA)) {
             if (parser == null) {
                 Log.w(TAG, "No " + DreamService.DREAM_META_DATA + " meta-data");
                 return null;
             }
-            Resources res = pm.getResourcesForApplication(resolveInfo.serviceInfo.applicationInfo);
+            Resources res = pm.getResourcesForApplication(serviceInfo.applicationInfo);
             AttributeSet attrs = Xml.asAttributeSet(parser);
-            int type;
-            while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
-                    && type != XmlPullParser.START_TAG) {
+            while (true) {
+                final int type = parser.next();
+                if (type == XmlPullParser.END_DOCUMENT || type == XmlPullParser.START_TAG) {
+                    break;
+                }
             }
             String nodeName = parser.getName();
             if (!"dream".equals(nodeName)) {
                 Log.w(TAG, "Meta-data does not start with dream tag");
                 return null;
             }
-            TypedArray sa = res.obtainAttributes(attrs, com.android.internal.R.styleable.Dream);
-            cn = sa.getString(com.android.internal.R.styleable.Dream_settingsActivity);
-            sa.recycle();
-        } catch (PackageManager.NameNotFoundException|IOException|XmlPullParserException e) {
-            caughtException = e;
-        } finally {
-            if (parser != null) parser.close();
-        }
-        if (caughtException != null) {
-            Log.w(TAG, "Error parsing : " + resolveInfo.serviceInfo.packageName, caughtException);
+            return res.obtainAttributes(attrs, com.android.internal.R.styleable.Dream);
+        } catch (PackageManager.NameNotFoundException | IOException | XmlPullParserException e) {
+            Log.w(TAG, "Error parsing : " + serviceInfo.packageName, e);
             return null;
         }
-        if (cn != null && cn.indexOf('/') < 0) {
-            cn = resolveInfo.serviceInfo.packageName + "/" + cn;
+    }
+
+    private static ComponentName convertToComponentName(String flattenedString,
+            ServiceInfo serviceInfo) {
+        if (flattenedString == null) return null;
+
+        if (flattenedString.indexOf('/') < 0) {
+            flattenedString = serviceInfo.packageName + "/" + flattenedString;
         }
-        return cn == null ? null : ComponentName.unflattenFromString(cn);
+        return ComponentName.unflattenFromString(flattenedString);
+    }
+
+    private static DreamMetadata getDreamMetadata(PackageManager pm, ResolveInfo resolveInfo) {
+        DreamMetadata result = new DreamMetadata();
+        if (resolveInfo == null) return result;
+        TypedArray rawMetadata = readMetadata(pm, resolveInfo.serviceInfo);
+        if (rawMetadata == null) return result;
+        result.mSettingsActivity = convertToComponentName(rawMetadata.getString(
+                com.android.internal.R.styleable.Dream_settingsActivity), resolveInfo.serviceInfo);
+        result.mPreviewImage = rawMetadata.getDrawable(
+                com.android.internal.R.styleable.Dream_previewImage);
+        rawMetadata.recycle();
+        return result;
     }
 
     private static void logd(String msg, Object... args) {
-        if (DEBUG)
+        if (DEBUG) {
             Log.d(TAG, args == null || args.length == 0 ? msg : String.format(msg, args));
+        }
     }
 
     private static class DreamInfoComparator implements Comparator<DreamInfo> {
diff --git a/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodSettingValuesWrapper.java b/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodSettingValuesWrapper.java
index 39e6dce..5860bda 100644
--- a/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodSettingValuesWrapper.java
+++ b/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodSettingValuesWrapper.java
@@ -27,6 +27,7 @@
 import android.view.inputmethod.InputMethodManager;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.inputmethod.DirectBootAwareness;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -88,7 +89,8 @@
 
     public void refreshAllInputMethodAndSubtypes() {
         mMethodList.clear();
-        mMethodList.addAll(mImm.getInputMethodListAsUser(mContentResolver.getUserId()));
+        mMethodList.addAll(mImm.getInputMethodListAsUser(
+                mContentResolver.getUserId(), DirectBootAwareness.ANY));
     }
 
     public List<InputMethodInfo> getInputMethodList() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/DataUsageController.java b/packages/SettingsLib/src/com/android/settingslib/net/DataUsageController.java
index 18c38c5..011ca0b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/net/DataUsageController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/net/DataUsageController.java
@@ -32,7 +32,6 @@
 import android.net.NetworkPolicy;
 import android.net.NetworkPolicyManager;
 import android.net.NetworkTemplate;
-import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
@@ -172,7 +171,7 @@
                 return bucket.getRxBytes() + bucket.getTxBytes();
             }
             Log.w(TAG, "Failed to get data usage, no entry data");
-        } catch (RemoteException e) {
+        } catch (RuntimeException e) {
             Log.w(TAG, "Failed to get data usage, remote call failed");
         }
         return -1L;
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleChartDataLoader.java b/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleChartDataLoader.java
index 787dc55..42e7100 100644
--- a/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleChartDataLoader.java
+++ b/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleChartDataLoader.java
@@ -18,7 +18,6 @@
 
 import android.app.usage.NetworkStats;
 import android.content.Context;
-import android.os.RemoteException;
 import android.util.Log;
 
 import java.util.ArrayList;
@@ -54,7 +53,7 @@
                     .setTotalUsage(total);
                 mData.add(builder.build());
             }
-        } catch (RemoteException e) {
+        } catch (RuntimeException e) {
             Log.e(TAG, "Exception querying network detail.", e);
         }
     }
@@ -85,7 +84,7 @@
                 if (bucket != null) {
                     usage = bucket.getRxBytes() + bucket.getTxBytes();
                 }
-            } catch (RemoteException e) {
+            } catch (RuntimeException e) {
                 Log.e(TAG, "Exception querying network detail.", e);
             }
             data.add(new NetworkCycleData.Builder()
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/NetworkStatsSummaryLoader.java b/packages/SettingsLib/src/com/android/settingslib/net/NetworkStatsSummaryLoader.java
index ed093629..54d5c3d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/net/NetworkStatsSummaryLoader.java
+++ b/packages/SettingsLib/src/com/android/settingslib/net/NetworkStatsSummaryLoader.java
@@ -20,7 +20,6 @@
 import android.app.usage.NetworkStatsManager;
 import android.content.Context;
 import android.net.NetworkTemplate;
-import android.os.RemoteException;
 import android.util.Log;
 
 import androidx.loader.content.AsyncTaskLoader;
@@ -55,7 +54,7 @@
     public NetworkStats loadInBackground() {
         try {
             return mNetworkStatsManager.querySummary(mNetworkTemplate, mStart, mEnd);
-        } catch (RemoteException e) {
+        } catch (RuntimeException e) {
             Log.e(TAG, "Exception querying network detail.", e);
             return null;
         }
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiEnterpriseRestrictionUtils.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiEnterpriseRestrictionUtils.java
new file mode 100644
index 0000000..21a4ac6
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiEnterpriseRestrictionUtils.java
@@ -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.settingslib.wifi;
+
+import android.content.Context;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.UserManager;
+import android.util.Log;
+
+import androidx.annotation.ChecksSdkIntAtLeast;
+
+/* Utility class is to confirm the Wi-Fi function is available by enterprise restriction */
+public class WifiEnterpriseRestrictionUtils {
+    private static final String TAG = "WifiEntResUtils";
+
+    /**
+     * Confirm Wi-Fi tethering is allowed according to whether user restriction is set
+     *
+     * @param context A context
+     * @return whether the device is permitted to use Wi-Fi Tethering
+     */
+    public static boolean isWifiTetheringAllowed(Context context) {
+        final UserManager userManager = context.getSystemService(UserManager.class);
+        final Bundle restrictions = userManager.getUserRestrictions();
+        if (isAtLeastT() && restrictions.getBoolean(UserManager.DISALLOW_WIFI_TETHERING)) {
+            Log.i(TAG, "Wi-Fi Tethering isn't available due to user restriction.");
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Confirm Wi-Fi Direct is allowed according to whether user restriction is set
+     *
+     * @param context A context
+     * @return whether the device is permitted to use Wi-Fi Direct
+     */
+    public static boolean isWifiDirectAllowed(Context context) {
+        final UserManager userManager = context.getSystemService(UserManager.class);
+        final Bundle restrictions = userManager.getUserRestrictions();
+        if (isAtLeastT() && restrictions.getBoolean(UserManager.DISALLOW_WIFI_DIRECT)) {
+            Log.i(TAG, "Wi-Fi Direct isn't available due to user restriction.");
+            return false;
+        }
+        return true;
+    }
+
+    @ChecksSdkIntAtLeast(api=Build.VERSION_CODES.TIRAMISU)
+    private static boolean isAtLeastT() {
+        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU;
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiRestrictionsCache.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiRestrictionsCache.java
new file mode 100644
index 0000000..7ffae40
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiRestrictionsCache.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.wifi;
+
+import static android.os.UserManager.DISALLOW_CONFIG_WIFI;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.os.Bundle;
+import android.os.UserManager;
+import android.util.SparseArray;
+
+import androidx.annotation.VisibleForTesting;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * This is a singleton class for Wi-Fi restrictions caching.
+ */
+public class WifiRestrictionsCache {
+    private static final String TAG = "WifiResCache";
+
+    /**
+     * Manages mapping between user ID and corresponding singleton {@link WifiRestrictionsCache}
+     * object.
+     */
+    @VisibleForTesting
+    protected static final SparseArray<WifiRestrictionsCache> sInstances = new SparseArray<>();
+
+    @VisibleForTesting
+    protected UserManager mUserManager;
+    @VisibleForTesting
+    protected Bundle mUserRestrictions;
+    @VisibleForTesting
+    protected final Map<String, Boolean> mRestrictions = new HashMap<>();
+
+    /**
+     * @return an instance of {@link WifiRestrictionsCache} object.
+     */
+    @NonNull
+    public static WifiRestrictionsCache getInstance(@NonNull Context context) {
+        final int requestUserId = context.getUserId();
+        WifiRestrictionsCache cache;
+        synchronized (sInstances) {
+            // We have same user context as request.
+            if (sInstances.indexOfKey(requestUserId) >= 0) {
+                return sInstances.get(requestUserId);
+            }
+            // Request by a new user context.
+            cache = new WifiRestrictionsCache(context);
+            sInstances.put(context.getUserId(), cache);
+        }
+        return cache;
+    }
+
+    /**
+     * Removes all the instances.
+     */
+    public static void clearInstance() {
+        synchronized (sInstances) {
+            for (int i = 0; i < sInstances.size(); i++) {
+                int key = sInstances.keyAt(i);
+                WifiRestrictionsCache cache = sInstances.get(key);
+                cache.clearRestrictions();
+                sInstances.remove(key);
+            }
+            sInstances.clear();
+        }
+    }
+
+    /**
+     * Constructor to create a singleton class for Wi-Fi restrictions cache.
+     *
+     * @param context The Context this is associated with.
+     */
+    protected WifiRestrictionsCache(@NonNull Context context) {
+        mUserManager = context.getSystemService(UserManager.class);
+        if (mUserManager != null) {
+            mUserRestrictions = mUserManager.getUserRestrictions();
+        }
+    }
+
+    /**
+     * @return the boolean value of the restrictions
+     */
+    public Boolean getRestriction(String key) {
+        if (mUserRestrictions == null) {
+            return false;
+        }
+        Boolean restriction;
+        synchronized (mRestrictions) {
+            if (mRestrictions.containsKey(key)) {
+                return mRestrictions.get(key);
+            }
+            restriction = mUserRestrictions.getBoolean(key);
+            mRestrictions.put(key, restriction);
+        }
+        return restriction;
+    }
+
+    /**
+     * Removes all the restrictions.
+     */
+    public void clearRestrictions() {
+        synchronized (mRestrictions) {
+            mRestrictions.clear();
+        }
+    }
+
+    /**
+     * @return Whether the user is allowed to config Wi-Fi.
+     */
+    public Boolean isConfigWifiAllowed() {
+        return !getRestriction(DISALLOW_CONFIG_WIFI);
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index bf5ab1c..426ea42 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -342,7 +342,8 @@
 
         resumeScanning();
         if (!mRegistered) {
-            mContext.registerReceiver(mReceiver, mFilter, null /* permission */, mWorkHandler);
+            mContext.registerReceiver(mReceiver, mFilter, null /* permission */, mWorkHandler,
+                    Context.RECEIVER_EXPORTED_UNAUDITED);
             // NetworkCallback objects cannot be reused. http://b/20701525 .
             mNetworkCallback = new WifiTrackerNetworkCallback();
             mConnectivityManager.registerNetworkCallback(
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
index d8f4d7f..55d125e 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
@@ -527,7 +527,7 @@
 
         // Set PAN profile to be disconnected and test connection state summary
         updateProfileStatus(mPanProfile, BluetoothProfile.STATE_DISCONNECTED);
-        assertThat(mCachedDevice.getCarConnectionSummary()).isNull();
+        assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Disconnected");
 
         // Test with battery level
         mBatteryLevel = 10;
@@ -537,7 +537,7 @@
 
         // Set PAN profile to be disconnected and test connection state summary
         updateProfileStatus(mPanProfile, BluetoothProfile.STATE_DISCONNECTED);
-        assertThat(mCachedDevice.getCarConnectionSummary()).isNull();
+        assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Disconnected");
 
         // Test with BluetoothDevice.BATTERY_LEVEL_UNKNOWN battery level
         mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN;
@@ -548,7 +548,7 @@
 
         // Set PAN profile to be disconnected and test connection state summary
         updateProfileStatus(mPanProfile, BluetoothProfile.STATE_DISCONNECTED);
-        assertThat(mCachedDevice.getCarConnectionSummary()).isNull();
+        assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Disconnected");
     }
 
     @Test
@@ -579,7 +579,7 @@
 
         // Disconnect all profiles and test connection state summary
         updateProfileStatus(mPanProfile, BluetoothProfile.STATE_DISCONNECTED);
-        assertThat(mCachedDevice.getCarConnectionSummary()).isNull();
+        assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Disconnected");
     }
 
     @Test
@@ -600,7 +600,7 @@
 
         // Set A2DP profile to be disconnected and test connection state summary
         updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
-        assertThat(mCachedDevice.getCarConnectionSummary()).isNull();
+        assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Disconnected");
 
         // Test with BluetoothDevice.BATTERY_LEVEL_UNKNOWN battery level
         mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN;
@@ -611,7 +611,7 @@
 
         // Set A2DP profile to be disconnected and test connection state summary
         updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
-        assertThat(mCachedDevice.getCarConnectionSummary()).isNull();
+        assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Disconnected");
     }
 
     @Test
@@ -632,7 +632,7 @@
 
         // Set HFP profile to be disconnected and test connection state summary
         updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
-        assertThat(mCachedDevice.getCarConnectionSummary()).isNull();
+        assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Disconnected");
 
         // Test with BluetoothDevice.BATTERY_LEVEL_UNKNOWN battery level
         mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN;
@@ -643,7 +643,7 @@
 
         // Set HFP profile to be disconnected and test connection state summary
         updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
-        assertThat(mCachedDevice.getCarConnectionSummary()).isNull();
+        assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Disconnected");
     }
 
     @Test
@@ -660,7 +660,7 @@
         // Set Hearing Aid profile to be disconnected and test connection state summary
         mCachedDevice.onActiveDeviceChanged(false, BluetoothProfile.HEARING_AID);
         updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_DISCONNECTED);
-        assertThat(mCachedDevice.getCarConnectionSummary()).isNull();
+        assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Disconnected");
     }
 
     @Test
@@ -707,9 +707,32 @@
         // Set A2DP and HFP profiles to be disconnected and test connection state summary
         updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
         updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
-        assertThat(mCachedDevice.getCarConnectionSummary()).isNull();
+        assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Disconnected");
     }
 
+    @Test
+    public void getCarConnectionSummary_shortSummary_returnShortSummary() {
+        // Test without battery level
+        // Set A2DP profile to be connected and test connection state summary
+        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+        assertThat(mCachedDevice.getCarConnectionSummary(true /* shortSummary */))
+                .isEqualTo("Connected");
+
+        // Set device as Active for A2DP and test connection state summary
+        mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP);
+        assertThat(mCachedDevice.getCarConnectionSummary(true /* shortSummary */))
+                .isEqualTo("Connected");
+
+        // Test with battery level
+        mBatteryLevel = 10;
+        assertThat(mCachedDevice.getCarConnectionSummary(true /* shortSummary */))
+                .isEqualTo("Connected");
+
+        // Set A2DP profile to be disconnected and test connection state summary
+        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
+        assertThat(mCachedDevice.getCarConnectionSummary(true /* shortSummary */))
+                .isEqualTo("Disconnected");
+    }
 
     @Test
     public void deviceName_testAliasNameAvailable() {
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiEnterpriseRestrictionUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiEnterpriseRestrictionUtilsTest.java
new file mode 100644
index 0000000..3c339de
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiEnterpriseRestrictionUtilsTest.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.wifi;
+
+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.os.Build;
+import android.os.Bundle;
+import android.os.UserManager;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.util.ReflectionHelpers;
+
+@RunWith(RobolectricTestRunner.class)
+public class WifiEnterpriseRestrictionUtilsTest {
+
+    private Context mContext;
+    @Mock
+    private UserManager mUserManager;
+    @Mock
+    private Bundle mBundle;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext = spy(ApplicationProvider.getApplicationContext());
+        when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
+        when(mUserManager.getUserRestrictions()).thenReturn(mBundle);
+    }
+
+    @Test
+    public void isWifiTetheringAllowed_setSDKForS_shouldReturnTrue() {
+        ReflectionHelpers.setStaticField(Build.VERSION.class, "SDK_INT", Build.VERSION_CODES.S);
+        when(mBundle.getBoolean(UserManager.DISALLOW_WIFI_TETHERING)).thenReturn(true);
+
+        assertThat(WifiEnterpriseRestrictionUtils.isWifiTetheringAllowed(mContext)).isTrue();
+    }
+
+    @Test
+    public void isWifiTetheringAllowed_setSDKForTAndDisallowForRestriction_shouldReturnFalse() {
+        ReflectionHelpers.setStaticField(
+                Build.VERSION.class, "SDK_INT", Build.VERSION_CODES.TIRAMISU);
+        when(mBundle.getBoolean(UserManager.DISALLOW_WIFI_TETHERING)).thenReturn(true);
+
+        assertThat(WifiEnterpriseRestrictionUtils.isWifiTetheringAllowed(mContext)).isFalse();
+    }
+
+    @Test
+    public void isWifiTetheringAllowed_setSDKForTAndAllowForRestriction_shouldReturnTrue() {
+        ReflectionHelpers.setStaticField(
+            Build.VERSION.class, "SDK_INT", Build.VERSION_CODES.TIRAMISU);
+        when(mBundle.getBoolean(UserManager.DISALLOW_WIFI_TETHERING)).thenReturn(false);
+
+        assertThat(WifiEnterpriseRestrictionUtils.isWifiTetheringAllowed(mContext)).isTrue();
+    }
+
+    @Test
+    public void isWifiDirectAllowed_setSDKForS_shouldReturnTrue() {
+        ReflectionHelpers.setStaticField(Build.VERSION.class, "SDK_INT", Build.VERSION_CODES.S);
+        when(mBundle.getBoolean(UserManager.DISALLOW_WIFI_DIRECT)).thenReturn(true);
+
+        assertThat(WifiEnterpriseRestrictionUtils.isWifiDirectAllowed(mContext)).isTrue();
+    }
+
+    @Test
+    public void isWifiDirectAllowed_setSDKForTAndDisallowForRestriction_shouldReturnFalse() {
+        ReflectionHelpers.setStaticField(
+            Build.VERSION.class, "SDK_INT", Build.VERSION_CODES.TIRAMISU);
+        when(mBundle.getBoolean(UserManager.DISALLOW_WIFI_DIRECT)).thenReturn(true);
+
+        assertThat(WifiEnterpriseRestrictionUtils.isWifiDirectAllowed(mContext)).isFalse();
+    }
+
+    @Test
+    public void isWifiDirectAllowed_setSDKForTAndAllowForRestriction_shouldReturnTrue() {
+        ReflectionHelpers.setStaticField(
+            Build.VERSION.class, "SDK_INT", Build.VERSION_CODES.TIRAMISU);
+        when(mBundle.getBoolean(UserManager.DISALLOW_WIFI_DIRECT)).thenReturn(false);
+
+        assertThat(WifiEnterpriseRestrictionUtils.isWifiDirectAllowed(mContext)).isTrue();
+    }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiRestrictionsCacheTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiRestrictionsCacheTest.java
new file mode 100644
index 0000000..404e0e8
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiRestrictionsCacheTest.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.wifi;
+
+import static android.os.UserManager.DISALLOW_CONFIG_WIFI;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.os.UserManager;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.robolectric.RobolectricTestRunner;
+
+@RunWith(RobolectricTestRunner.class)
+public class WifiRestrictionsCacheTest {
+
+    private static final int USER_OWNER = 0;
+    private static final int USER_1 = 1;
+    private static final int USER_2 = 2;
+    private static final int USER_3 = 3;
+    private static final int USER_GUEST = 10;
+
+    @Rule
+    public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+    @Mock
+    UserManager mUserManager;
+    @Mock
+    Bundle mUserRestrictionsOwner;
+    @Mock
+    Bundle mUserRestrictionsGuest;
+
+    private Context mContext;
+    private WifiRestrictionsCache mWifiRestrictionsCacheOwner;
+    private WifiRestrictionsCache mWifiRestrictionsCacheGuest;
+
+    @Before
+    public void setUp() {
+        mContext = spy(ApplicationProvider.getApplicationContext());
+        when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
+
+        when(mContext.getUserId()).thenReturn(USER_OWNER);
+        when(mUserManager.getUserRestrictions()).thenReturn(mUserRestrictionsOwner);
+        when(mUserRestrictionsOwner.getBoolean(anyString())).thenReturn(false);
+        mWifiRestrictionsCacheOwner = WifiRestrictionsCache.getInstance(mContext);
+
+        when(mContext.getUserId()).thenReturn(USER_GUEST);
+        when(mUserManager.getUserRestrictions()).thenReturn(mUserRestrictionsGuest);
+        when(mUserRestrictionsGuest.getBoolean(anyString())).thenReturn(true);
+        mWifiRestrictionsCacheGuest = WifiRestrictionsCache.getInstance(mContext);
+    }
+
+    @After
+    public void tearDown() {
+        WifiRestrictionsCache.clearInstance();
+    }
+
+    @Test
+    public void getInstance_sameUserId_sameInstance() {
+        when(mContext.getUserId()).thenReturn(USER_OWNER);
+        WifiRestrictionsCache instance1 = WifiRestrictionsCache.getInstance(mContext);
+
+        WifiRestrictionsCache instance2 = WifiRestrictionsCache.getInstance(mContext);
+
+        assertThat(instance1).isEqualTo(instance2);
+    }
+
+    @Test
+    public void getInstance_diffUserId_diffInstance() {
+        when(mContext.getUserId()).thenReturn(USER_OWNER);
+        WifiRestrictionsCache instance1 = WifiRestrictionsCache.getInstance(mContext);
+
+        when(mContext.getUserId()).thenReturn(USER_GUEST);
+        WifiRestrictionsCache instance2 = WifiRestrictionsCache.getInstance(mContext);
+
+        assertThat(instance1).isNotEqualTo(instance2);
+    }
+
+    @Test
+    public void clearInstance_instanceShouldBeEmpty() {
+        WifiRestrictionsCache.clearInstance();
+
+        assertThat(WifiRestrictionsCache.sInstances.size()).isEqualTo(0);
+    }
+
+    @Test
+    public void getRestriction_firstTime_getFromSystem() {
+        Bundle userRestrictions = mock(Bundle.class);
+        WifiRestrictionsCache wifiRestrictionsCache = mockInstance(USER_1, userRestrictions);
+
+        wifiRestrictionsCache.getRestriction(DISALLOW_CONFIG_WIFI);
+
+        verify(userRestrictions).getBoolean(DISALLOW_CONFIG_WIFI);
+    }
+
+    @Test
+    public void getRestriction_secondTime_notGetFromSystem() {
+        Bundle userRestrictions = mock(Bundle.class);
+        WifiRestrictionsCache wifiRestrictionsCache = mockInstance(USER_2, userRestrictions);
+        // First time to get the restriction value
+        wifiRestrictionsCache.getRestriction(DISALLOW_CONFIG_WIFI);
+        reset(userRestrictions);
+
+        // Second time to get the restriction value
+        wifiRestrictionsCache.getRestriction(DISALLOW_CONFIG_WIFI);
+
+        verify(userRestrictions, never()).getBoolean(DISALLOW_CONFIG_WIFI);
+    }
+
+    @Test
+    public void clearRestrictions_shouldGetRestrictionFromSystemAgain() {
+        Bundle userRestrictions = mock(Bundle.class);
+        WifiRestrictionsCache wifiRestrictionsCache = mockInstance(USER_3, userRestrictions);
+        // First time to get the restriction value
+        wifiRestrictionsCache.getRestriction(DISALLOW_CONFIG_WIFI);
+        reset(userRestrictions);
+
+        // Clear the cache and then second time to get the restriction value
+        wifiRestrictionsCache.clearRestrictions();
+        wifiRestrictionsCache.getRestriction(DISALLOW_CONFIG_WIFI);
+
+        verify(userRestrictions).getBoolean(DISALLOW_CONFIG_WIFI);
+    }
+
+    @Test
+    public void isConfigWifiAllowed_ownerUser_returnTrue() {
+        assertThat(mWifiRestrictionsCacheOwner.isConfigWifiAllowed()).isTrue();
+    }
+
+    @Test
+    public void isConfigWifiAllowed_guestUser_returnFalse() {
+        assertThat(mWifiRestrictionsCacheGuest.isConfigWifiAllowed()).isFalse();
+    }
+
+    private WifiRestrictionsCache mockInstance(int userId, Bundle userRestrictions) {
+        when(mContext.getUserId()).thenReturn(userId);
+        when(mUserManager.getUserRestrictions()).thenReturn(userRestrictions);
+        return WifiRestrictionsCache.getInstance(mContext);
+    }
+}
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index 4e2111c..16cece9 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -188,6 +188,7 @@
         Settings.Secure.ACCESSIBILITY_FLOATING_MENU_ICON_TYPE,
         Settings.Secure.ACCESSIBILITY_FLOATING_MENU_OPACITY,
         Settings.Secure.ACCESSIBILITY_FLOATING_MENU_FADE_ENABLED,
+        Settings.Secure.ODI_CAPTIONS_VOLUME_UI_ENABLED,
         Settings.Secure.NOTIFICATION_BUBBLES,
         Settings.Secure.LOCATION_TIME_ZONE_DETECTION_ENABLED,
         Settings.Secure.LOCKSCREEN_SHOW_CONTROLS,
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index dd1cb6b..13c1e51 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -229,6 +229,7 @@
         VALIDATORS.put(Secure.SKIP_DIRECTION, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.SILENCE_GESTURE, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES, JSON_OBJECT_VALIDATOR);
+        VALIDATORS.put(Secure.NAV_BAR_KIDS_MODE, BOOLEAN_VALIDATOR);
         VALIDATORS.put(
                 Secure.NAVIGATION_MODE, new DiscreteValueValidator(new String[] {"0", "1", "2"}));
         VALIDATORS.put(Secure.BACK_GESTURE_INSET_SCALE_LEFT,
@@ -321,5 +322,7 @@
             }
             return true;
         });
+        VALIDATORS.put(Secure.ODI_CAPTIONS_VOLUME_UI_ENABLED, BOOLEAN_VALIDATOR);
+
     }
 }
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index cdf274f..dec3245 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -1348,7 +1348,6 @@
                             Settings.Global.CONNECTIVITY_CHANGE_DELAY,
                             Settings.Global.CAPTIVE_PORTAL_DETECTION_ENABLED,
                             Settings.Global.CAPTIVE_PORTAL_SERVER,
-                            Settings.Global.NSD_ON,
                             Settings.Global.SET_INSTALL_LOCATION,
                             Settings.Global.DEFAULT_INSTALL_LOCATION,
                             Settings.Global.INET_CONDITION_DEBOUNCE_UP_DELAY,
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 6072f68..cd6447f 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -244,9 +244,6 @@
 
         final long autofillToken = p.start(GlobalSettingsProto.AUTOFILL);
         dumpSetting(s, p,
-                Settings.Global.AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES,
-                GlobalSettingsProto.Autofill.COMPAT_MODE_ALLOWED_PACKAGES);
-        dumpSetting(s, p,
                 Settings.Global.AUTOFILL_LOGGING_LEVEL,
                 GlobalSettingsProto.Autofill.LOGGING_LEVEL);
         dumpSetting(s, p,
@@ -1100,10 +1097,6 @@
         p.end(notificationToken);
 
         dumpSetting(s, p,
-                Settings.Global.NSD_ON,
-                GlobalSettingsProto.NSD_ON);
-
-        dumpSetting(s, p,
                 Settings.Global.NR_NSA_TRACKING_SCREEN_OFF_MODE,
                 GlobalSettingsProto.NR_NSA_TRACKING_SCREEN_OFF_MODE);
 
@@ -1817,6 +1810,9 @@
         dumpSetting(s, p,
                 Settings.Secure.ACCESSIBILITY_FLOATING_MENU_FADE_ENABLED,
                 SecureSettingsProto.Accessibility.ACCESSIBILITY_FLOATING_MENU_FADE_ENABLED);
+        dumpSetting(s, p,
+                Settings.Secure.ODI_CAPTIONS_VOLUME_UI_ENABLED,
+                SecureSettingsProto.Accessibility.ODI_CAPTIONS_VOLUME_UI_ENABLED);
         p.end(accessibilityToken);
 
         final long adaptiveSleepToken = p.start(SecureSettingsProto.ADAPTIVE_SLEEP);
@@ -2248,6 +2244,10 @@
                 SecureSettingsProto.MULTI_PRESS_TIMEOUT);
 
         dumpSetting(s, p,
+                Settings.Secure.NAV_BAR_KIDS_MODE,
+                SecureSettingsProto.NAV_BAR_KIDS_MODE);
+
+        dumpSetting(s, p,
                 Settings.Secure.NAVIGATION_MODE,
                 SecureSettingsProto.NAVIGATION_MODE);
 
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 1e2d4e9..927f11f 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -2117,7 +2117,7 @@
         }
         if ((ai.flags & ApplicationInfo.FLAG_TEST_ONLY) == 0) {
             // Skip checking readable annotations for test_only apps
-            checkReadableAnnotation(settingsType, settingName, ai.targetSandboxVersion);
+            checkReadableAnnotation(settingsType, settingName, ai.targetSdkVersion);
         }
         /**
          * some settings need additional permission check, this is to have a matching security
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 2d1f0cb..a3f3995 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -134,7 +134,6 @@
                     Settings.Global.ART_VERIFIER_VERIFY_DEBUGGABLE,
                     Settings.Global.ASSISTED_GPS_ENABLED,
                     Settings.Global.AUDIO_SAFE_VOLUME_STATE,
-                    Settings.Global.AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES,
                     Settings.Global.AUTOFILL_LOGGING_LEVEL,
                     Settings.Global.AUTOFILL_MAX_PARTITIONS_SIZE,
                     Settings.Global.AUTOFILL_MAX_VISIBLE_DATASETS,
@@ -391,7 +390,6 @@
                     Settings.Global.NOTIFICATION_SNOOZE_OPTIONS,
                     Settings.Global.NOTIFICATION_FEEDBACK_ENABLED,
                     Settings.Global.NR_NSA_TRACKING_SCREEN_OFF_MODE,
-                    Settings.Global.NSD_ON,
                     Settings.Global.NTP_SERVER,
                     Settings.Global.NTP_TIMEOUT,
                     Settings.Global.OTA_DISABLE_AUTOMATIC_UPDATE,
@@ -658,6 +656,7 @@
                     Settings.Global.Wearable.WRIST_ORIENTATION_MODE,
                     Settings.Global.Wearable.CLOCKWORK_SYSUI_PACKAGE,
                     Settings.Global.Wearable.CLOCKWORK_SYSUI_MAIN_ACTIVITY,
+                    Settings.Global.Wearable.CLOCKWORK_LONG_PRESS_TO_ASSISTANT_ENABLED,
                     Settings.Global.Wearable.WEAR_ACTIVITY_AUTO_RESUME_TIMEOUT_SET_BY_USER);
 
     private static final Set<String> BACKUP_DENY_LIST_SECURE_SETTINGS =
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index a3f07d8..10252ee 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -610,6 +610,9 @@
     <!-- Permission required for CTS test - CtsSafetyCenterTestCases -->
     <uses-permission android:name="android.permission.SEND_SAFETY_CENTER_UPDATE" />
 
+    <!-- Permission required for CTS test - CtsSafetyCenterTestCases -->
+    <uses-permission android:name="android.permission.READ_SAFETY_CENTER_STATUS" />
+
     <!-- Permission required for CTS test - CommunalManagerTest -->
     <uses-permission android:name="android.permission.WRITE_COMMUNAL_STATE" />
     <uses-permission android:name="android.permission.READ_COMMUNAL_STATE" />
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index 559c31a..b19ef3a 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -234,15 +234,23 @@
     plugins: ["dagger2-compiler"],
 }
 
-soong_config_module_type_import {
-    from: "frameworks/base/services/Android.bp",
-    module_types: ["system_optimized_java_defaults"],
+// Opt-in config for optimizing the SystemUI target using R8.
+// Enabled via `export SYSTEMUI_OPTIMIZE_JAVA=true`, or explicitly in Make via
+// the `SOONG_CONFIG_ANDROID_SYSTEMUI_OPTIMIZE_JAVA` variable.
+// TODO(b/203472868): Enable optimizations by default after stabilizing and
+// building out retrace infrastructure.
+soong_config_module_type {
+    name: "systemui_optimized_java_defaults",
+    module_type: "java_defaults",
+    config_namespace: "ANDROID",
+    bool_variables: ["SYSTEMUI_OPTIMIZE_JAVA"],
+    properties: ["optimize"],
 }
 
-system_optimized_java_defaults {
+systemui_optimized_java_defaults {
     name: "SystemUI_app_defaults",
     soong_config_variables: {
-        SYSTEM_OPTIMIZE_JAVA: {
+        SYSTEMUI_OPTIMIZE_JAVA: {
             optimize: {
                 enabled: true,
                 optimize: true,
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 1e9a41e..e907efb 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -260,6 +260,8 @@
     <uses-permission android:name="android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS" />
     <!-- For handling silent audio recordings -->
     <uses-permission android:name="android.permission.MODIFY_AUDIO_ROUTING" />
+    <!-- For asking AudioManager audio information -->
+    <uses-permission android:name="android.permission.QUERY_AUDIO_STATE"/>
 
     <!-- to read and change hvac values in a car -->
     <uses-permission android:name="android.car.permission.CONTROL_CAR_CLIMATE" />
diff --git a/packages/SystemUI/docs/qs-tiles.md b/packages/SystemUI/docs/qs-tiles.md
index efcb2de..4cb765d 100644
--- a/packages/SystemUI/docs/qs-tiles.md
+++ b/packages/SystemUI/docs/qs-tiles.md
@@ -357,10 +357,12 @@
   Updates the `State` of the Tile based on the state of the device as provided by the respective controller. It will be called every time the Tile becomes visible, is interacted with or `QSTileImpl#refreshState` is called. After this is done, the updated state will be reflected in the UI.
 
 * ```java
+  @Deprecated
   public int getMetricsCategory()
   ```
 
-  Identifier for this Tile, as defined in [proto/src/metrics_constants/metrics_constants.proto](/proto/src/metrics_constants/metrics_constants.proto). This is used to log events related to this Tile.
+  ~~Identifier for this Tile, as defined in [proto/src/metrics_constants/metrics_constants.proto](/proto/src/metrics_constants/metrics_constants.proto). This is used to log events related to this Tile.~~
+  This is now deprecated in favor of `UiEvent` that use the tile spec.
 
 * ```java
   public boolean isAvailable()
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
index d5f858c..8ad2009 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
@@ -34,7 +34,7 @@
 
     String ACTION = "com.android.systemui.action.PLUGIN_QS";
 
-    int VERSION = 12;
+    int VERSION = 13;
 
     String TAG = "QS";
 
@@ -70,6 +70,11 @@
     void setContainerController(QSContainerController controller);
     void setExpandClickListener(OnClickListener onClickListener);
 
+    /**
+     * Returns the height difference between the QSPanel container and the QuickQSPanel container
+     */
+    int getHeightDiff();
+
     View getHeader();
 
     default void setHasNotifications(boolean hasNotifications) {
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
index 77018d7..ffac26b 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
@@ -40,7 +40,7 @@
 @DependsOn(target = Icon.class)
 @DependsOn(target = State.class)
 public interface QSTile {
-    int VERSION = 1;
+    int VERSION = 2;
 
     DetailAdapter getDetailAdapter();
     String getTileSpec();
@@ -79,6 +79,12 @@
     void longClick(@Nullable View view);
 
     void userSwitch(int currentUser);
+
+    /**
+     * @deprecated not needed as {@link com.android.internal.logging.UiEvent} will use
+     * {@link #getMetricsSpec}
+     */
+    @Deprecated
     int getMetricsCategory();
 
     void setListening(Object client, boolean listening);
@@ -117,7 +123,6 @@
         void onShowDetail(boolean show);
         void onToggleStateChanged(boolean state);
         void onScanStateChanged(boolean state);
-        void onAnnouncementRequested(CharSequence announcement);
     }
 
     @ProvidesInterface(version = Icon.VERSION)
diff --git a/packages/SystemUI/res-keyguard/drawable/keyguard_user_switcher_header_bg.xml b/packages/SystemUI/res-keyguard/drawable/bouncer_user_switcher_header_bg.xml
similarity index 91%
rename from packages/SystemUI/res-keyguard/drawable/keyguard_user_switcher_header_bg.xml
rename to packages/SystemUI/res-keyguard/drawable/bouncer_user_switcher_header_bg.xml
index 177f695..1119935 100644
--- a/packages/SystemUI/res-keyguard/drawable/keyguard_user_switcher_header_bg.xml
+++ b/packages/SystemUI/res-keyguard/drawable/bouncer_user_switcher_header_bg.xml
@@ -17,14 +17,14 @@
 <layer-list xmlns:android="http://schemas.android.com/apk/res/android"
             xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
             android:paddingMode="stack"
-            android:paddingStart="44dp"
+            android:paddingStart="24dp"
             android:paddingEnd="44dp"
             android:paddingLeft="0dp"
             android:paddingRight="0dp">
     <item>
         <shape android:shape="rectangle">
           <solid android:color="?androidprv:attr/colorSurface" />
-            <corners android:radius="@dimen/keyguard_user_switcher_corner" />
+            <corners android:radius="32dp" />
         </shape>
     </item>
     <item
diff --git a/packages/SystemUI/res-keyguard/drawable/bouncer_user_switcher_item_selected_bg.xml b/packages/SystemUI/res-keyguard/drawable/bouncer_user_switcher_item_selected_bg.xml
new file mode 100644
index 0000000..5bb5690
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/drawable/bouncer_user_switcher_item_selected_bg.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<shape android:shape="rectangle"
+       xmlns:android="http://schemas.android.com/apk/res/android"
+       xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
+  <solid android:color="?androidprv:attr/colorAccentPrimary" />
+  <corners android:radius="24dp" />
+</shape>
diff --git a/packages/SystemUI/res-keyguard/drawable/keyguard_user_switcher_popup_bg.xml b/packages/SystemUI/res-keyguard/drawable/bouncer_user_switcher_popup_bg.xml
similarity index 92%
rename from packages/SystemUI/res-keyguard/drawable/keyguard_user_switcher_popup_bg.xml
rename to packages/SystemUI/res-keyguard/drawable/bouncer_user_switcher_popup_bg.xml
index 96a2d15..74ece15 100644
--- a/packages/SystemUI/res-keyguard/drawable/keyguard_user_switcher_popup_bg.xml
+++ b/packages/SystemUI/res-keyguard/drawable/bouncer_user_switcher_popup_bg.xml
@@ -18,5 +18,5 @@
        xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
        android:shape="rectangle">
     <solid android:color="?androidprv:attr/colorSurface" />
-    <corners android:radius="@dimen/keyguard_user_switcher_popup_corner" />
+    <corners android:radius="28dp" />
 </shape>
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_bouncer.xml b/packages/SystemUI/res-keyguard/layout/keyguard_bouncer.xml
deleted file mode 100644
index 384e02d..0000000
--- a/packages/SystemUI/res-keyguard/layout/keyguard_bouncer.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?><!--
-  ~ 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
-  -->
-
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:background="@android:color/transparent"
-    android:clipChildren="false"
-    android:clipToPadding="false">
-
-    <include
-        layout="@layout/keyguard_host_view"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content" />
-</FrameLayout>
-
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_user_switcher.xml b/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_user_switcher.xml
index 4f0925f..36035fc 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_user_switcher.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_user_switcher.xml
@@ -30,8 +30,8 @@
 
     <ImageView
         android:id="@+id/user_icon"
-        android:layout_width="@dimen/keyguard_user_switcher_icon_size"
-        android:layout_height="@dimen/keyguard_user_switcher_icon_size" />
+        android:layout_width="@dimen/bouncer_user_switcher_icon_size"
+        android:layout_height="@dimen/bouncer_user_switcher_icon_size" />
 
     <!-- need to keep this outer view in order to have a correctly sized anchor
          for the dropdown menu, as well as dropdown background in the right place -->
@@ -40,13 +40,12 @@
         android:orientation="horizontal"
         android:layout_height="wrap_content"
         android:layout_width="wrap_content"
-        android:layout_marginTop="30dp"
-        android:minHeight="48dp">
+        android:layout_marginTop="30dp">
       <TextView
-          style="@style/Keyguard.UserSwitcher.Spinner.Header"
+          style="@style/Bouncer.UserSwitcher.Spinner.Header"
           android:clickable="false"
           android:id="@+id/user_switcher_header"
-          android:layout_width="@dimen/keyguard_user_switcher_width"
+          android:layout_width="@dimen/bouncer_user_switcher_width"
           android:layout_height="wrap_content" />
     </LinearLayout>>
 
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_user_switcher_item.xml b/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_user_switcher_item.xml
index b08e1ff..c388f15 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_user_switcher_item.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_user_switcher_item.xml
@@ -13,13 +13,14 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<TextView
+<FrameLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
-    style="@style/Keyguard.UserSwitcher.Spinner.Item"
     android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:layout_gravity="start"
-    android:paddingStart="@dimen/control_menu_horizontal_padding"
-    android:paddingEnd="@dimen/control_menu_horizontal_padding"
-    android:textDirection="locale"/>
-
+    android:layout_height="wrap_content">
+  <TextView
+      style="@style/Bouncer.UserSwitcher.Spinner.Item"
+      android:layout_width="match_parent"
+      android:layout_height="wrap_content"
+      android:layout_marginStart="12dp"
+      android:layout_marginEnd="12dp" />
+</FrameLayout>
diff --git a/packages/SystemUI/res-keyguard/values/dimens.xml b/packages/SystemUI/res-keyguard/values/dimens.xml
index 2819dc9..c8bb8e9 100644
--- a/packages/SystemUI/res-keyguard/values/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values/dimens.xml
@@ -108,11 +108,15 @@
     <dimen name="one_handed_bouncer_move_animation_translation">120dp</dimen>
 
 
-    <dimen name="keyguard_user_switcher_header_text_size">32sp</dimen>
-    <dimen name="keyguard_user_switcher_item_text_size">32sp</dimen>
-    <dimen name="keyguard_user_switcher_width">320dp</dimen>
-    <dimen name="keyguard_user_switcher_icon_size">310dp</dimen>
-    <dimen name="keyguard_user_switcher_corner">32dp</dimen>
-    <dimen name="keyguard_user_switcher_popup_corner">24dp</dimen>
-    <dimen name="keyguard_user_switcher_item_padding_vertical">15dp</dimen>
+    <dimen name="bouncer_user_switcher_header_text_size">20sp</dimen>
+    <dimen name="bouncer_user_switcher_item_text_size">20sp</dimen>
+    <dimen name="bouncer_user_switcher_item_line_height">24sp</dimen>
+    <dimen name="bouncer_user_switcher_item_icon_size">28dp</dimen>
+    <dimen name="bouncer_user_switcher_item_icon_padding">12dp</dimen>
+    <dimen name="bouncer_user_switcher_width">248dp</dimen>
+    <dimen name="bouncer_user_switcher_icon_size">190dp</dimen>
+    <dimen name="bouncer_user_switcher_popup_header_height">12dp</dimen>
+    <dimen name="bouncer_user_switcher_popup_divider_height">4dp</dimen>
+    <dimen name="bouncer_user_switcher_item_padding_vertical">10dp</dimen>
+    <dimen name="bouncer_user_switcher_item_padding_horizontal">12dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res-keyguard/values/styles.xml b/packages/SystemUI/res-keyguard/values/styles.xml
index 60f034a..5048f85 100644
--- a/packages/SystemUI/res-keyguard/values/styles.xml
+++ b/packages/SystemUI/res-keyguard/values/styles.xml
@@ -141,22 +141,23 @@
         <item name="android:shadowRadius">0</item>
     </style>
 
-    <style name="Keyguard.UserSwitcher.Spinner" parent="@android:style/Widget.DeviceDefault.TextView">
+    <style name="Bouncer.UserSwitcher.Spinner" parent="@android:style/Widget.DeviceDefault.TextView">
         <item name="android:textColor">?android:attr/textColorPrimary</item>
-        <item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item>
         <item name="android:singleLine">true</item>
         <item name="android:ellipsize">end</item>
-        <item name="android:paddingTop">@dimen/keyguard_user_switcher_item_padding_vertical</item>
-        <item name="android:paddingBottom">@dimen/keyguard_user_switcher_item_padding_vertical</item>
+        <item name="android:minHeight">48dp</item>
+        <item name="android:paddingVertical">@dimen/bouncer_user_switcher_item_padding_vertical</item>
+        <item name="android:paddingHorizontal">@dimen/bouncer_user_switcher_item_padding_horizontal</item>
+        <item name="android:lineHeight">@dimen/bouncer_user_switcher_item_line_height</item>
+        <item name="android:gravity">start|center_vertical</item>
     </style>
 
-    <style name="Keyguard.UserSwitcher.Spinner.Header">
-        <item name="android:background">@drawable/keyguard_user_switcher_header_bg</item>
-        <item name="android:textSize">@dimen/keyguard_user_switcher_header_text_size</item>
+    <style name="Bouncer.UserSwitcher.Spinner.Header">
+        <item name="android:background">@drawable/bouncer_user_switcher_header_bg</item>
+        <item name="android:textSize">@dimen/bouncer_user_switcher_header_text_size</item>
     </style>
 
-    <style name="Keyguard.UserSwitcher.Spinner.Item">
-        <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
-        <item name="android:textSize">@dimen/keyguard_user_switcher_item_text_size</item>
+    <style name="Bouncer.UserSwitcher.Spinner.Item">
+        <item name="android:textSize">@dimen/bouncer_user_switcher_item_text_size</item>
     </style>
 </resources>
diff --git a/packages/SystemUI/res/drawable/ic_circle_check_box.xml b/packages/SystemUI/res/drawable/ic_circle_check_box.xml
new file mode 100644
index 0000000..b44a32d
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_circle_check_box.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.
+  -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item
+        android:id="@+id/checked"
+        android:state_checked="true"
+        android:drawable="@drawable/media_output_status_check" />
+    <item
+        android:id="@+id/unchecked"
+        android:state_checked="false"
+        android:drawable="@drawable/ic_circular_unchecked" />
+</selector>
diff --git a/packages/SystemUI/res/drawable/ic_circular_unchecked.xml b/packages/SystemUI/res/drawable/ic_circular_unchecked.xml
new file mode 100644
index 0000000..9b43cf6
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_circular_unchecked.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:fillColor="@color/media_dialog_inactive_item_main_content"
+      android:pathData="M12,22q-2.075,0 -3.9,-0.788 -1.825,-0.787 -3.175,-2.137 -1.35,-1.35 -2.137,-3.175Q2,14.075 2,12t0.788,-3.9q0.787,-1.825 2.137,-3.175 1.35,-1.35 3.175,-2.137Q9.925,2 12,2t3.9,0.788q1.825,0.787 3.175,2.137 1.35,1.35 2.137,3.175Q22,9.925 22,12t-0.788,3.9q-0.787,1.825 -2.137,3.175 -1.35,1.35 -3.175,2.137Q14.075,22 12,22zM12,12zM12,20q3.325,0 5.663,-2.337Q20,15.325 20,12t-2.337,-5.662Q15.325,4 12,4T6.338,6.338Q4,8.675 4,12q0,3.325 2.338,5.663Q8.675,20 12,20z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_color_correction.xml b/packages/SystemUI/res/drawable/ic_qs_color_correction.xml
new file mode 100644
index 0000000..f83cabd
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_color_correction.xml
@@ -0,0 +1,24 @@
+<!--
+    Copyright (C) 2022 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+    <path
+        android:fillColor="#ffffff"
+        android:pathData="M3,21v-4.75l8.95,-8.95 -1.45,-1.4 1.45,-1.4 1.9,1.9 3.1,-3.1q0.275,-0.275 0.7,-0.275 0.425,0 0.7,0.275l2.35,2.35q0.275,0.275 0.275,0.7 0,0.425 -0.275,0.7l-3.075,3.075 1.9,1.95L18.1,13.5l-1.4,-1.45L7.75,21zM5,19h1.95l8.3,-8.35 -1.9,-1.9L5,17.05z"/>
+</vector>
diff --git a/packages/SystemUI/res-keyguard/drawable/keyguard_user_switcher_popup_bg.xml b/packages/SystemUI/res/drawable/media_ttt_chip_background_receiver.xml
similarity index 65%
copy from packages/SystemUI/res-keyguard/drawable/keyguard_user_switcher_popup_bg.xml
copy to packages/SystemUI/res/drawable/media_ttt_chip_background_receiver.xml
index 96a2d15..708bc1a 100644
--- a/packages/SystemUI/res-keyguard/drawable/keyguard_user_switcher_popup_bg.xml
+++ b/packages/SystemUI/res/drawable/media_ttt_chip_background_receiver.xml
@@ -1,4 +1,3 @@
-<?xml version="1.0" encoding="utf-8"?>
 <!--
   ~ Copyright (C) 2021 The Android Open Source Project
   ~
@@ -12,11 +11,16 @@
   ~ distributed under the License is distributed on an "AS IS" BASIS,
   ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   ~ See the License for the specific language governing permissions and
-  ~ limitations under the License
+  ~ limitations under the License.
   -->
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
-       xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
-       android:shape="rectangle">
+
+<shape
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+    android:shape="oval">
+    <size
+        android:height="@dimen/media_ttt_chip_size_receiver"
+        android:width="@dimen/media_ttt_chip_size_receiver"
+        />
     <solid android:color="?androidprv:attr/colorSurface" />
-    <corners android:radius="@dimen/keyguard_user_switcher_popup_corner" />
 </shape>
diff --git a/packages/SystemUI/res-keyguard/drawable/keyguard_user_switcher_popup_bg.xml b/packages/SystemUI/res/drawable/qs_media_round_button_background.xml
similarity index 60%
copy from packages/SystemUI/res-keyguard/drawable/keyguard_user_switcher_popup_bg.xml
copy to packages/SystemUI/res/drawable/qs_media_round_button_background.xml
index 96a2d15..33ad2d6 100644
--- a/packages/SystemUI/res-keyguard/drawable/keyguard_user_switcher_popup_bg.xml
+++ b/packages/SystemUI/res/drawable/qs_media_round_button_background.xml
@@ -12,11 +12,14 @@
   ~ distributed under the License is distributed on an "AS IS" BASIS,
   ~ WITHOUT 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.
   -->
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
-       xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
-       android:shape="rectangle">
-    <solid android:color="?androidprv:attr/colorSurface" />
-    <corners android:radius="@dimen/keyguard_user_switcher_popup_corner" />
-</shape>
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+        android:color="@color/media_seamless_border">
+    <item android:id="@android:id/background">
+        <shape android:shape="oval">
+            <solid android:color="@color/media_seamless_border" />
+            <size android:width="48dp" android:height="48dp" />
+        </shape>
+    </item>
+</ripple>
diff --git a/packages/SystemUI/res/layout/dream_overlay_container.xml b/packages/SystemUI/res/layout/dream_overlay_container.xml
index b611ffa..4929f50 100644
--- a/packages/SystemUI/res/layout/dream_overlay_container.xml
+++ b/packages/SystemUI/res/layout/dream_overlay_container.xml
@@ -32,8 +32,8 @@
         android:id="@+id/dream_overlay_status_bar"
         android:layout_width="match_parent"
         android:layout_height="@dimen/dream_overlay_status_bar_height"
-        android:layout_marginEnd="@dimen/dream_overlay_status_bar_margin"
-        android:layout_marginStart="@dimen/dream_overlay_status_bar_margin"
+        android:paddingEnd="@dimen/dream_overlay_status_bar_margin"
+        android:paddingStart="@dimen/dream_overlay_status_bar_margin"
         app:layout_constraintTop_toTopOf="parent">
 
         <androidx.constraintlayout.widget.ConstraintLayout
diff --git a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
index baf5336..e69582f 100644
--- a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
+++ b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
@@ -53,21 +53,22 @@
     </LinearLayout>
 
     <LinearLayout
-        android:layout_width="match_parent"
+        android:layout_width="@dimen/internet_dialog_progress_bar_width"
         android:layout_height="wrap_content"
+        android:layout_gravity="center_horizontal"
         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_width="match_parent"
             android:layout_height="4dp"
+            android:layout_gravity="center_vertical|center_horizontal"
             android:background="?androidprv:attr/colorSurfaceVariant"/>
 
         <ProgressBar
             android:id="@+id/wifi_searching_progress"
-            android:layout_width="340dp"
+            android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:layout_gravity="center_horizontal"
             android:visibility="gone"
diff --git a/packages/SystemUI/res/layout/media_output_list_item.xml b/packages/SystemUI/res/layout/media_output_list_item.xml
index 8931689..806804f 100644
--- a/packages/SystemUI/res/layout/media_output_list_item.xml
+++ b/packages/SystemUI/res/layout/media_output_list_item.xml
@@ -96,26 +96,6 @@
                 android:textSize="14sp"
                 android:fontFamily="@*android:string/config_bodyFontFamily"
                 android:visibility="gone"/>
-            <ImageView
-                android:id="@+id/add_icon"
-                android:layout_width="24dp"
-                android:layout_height="24dp"
-                android:layout_gravity="right"
-                android:layout_marginEnd="16dp"
-                android:layout_alignParentRight="true"
-                android:src="@drawable/ic_add"
-                android:tint="?android:attr/colorAccent"
-            />
-            <CheckBox
-                android:id="@+id/check_box"
-                android:layout_width="24dp"
-                android:layout_height="24dp"
-                android:layout_gravity="right"
-                android:layout_marginEnd="16dp"
-                android:layout_alignParentRight="true"
-                android:button="@drawable/ic_check_box"
-                android:visibility="gone"
-            />
         </RelativeLayout>
 
         <ProgressBar
@@ -139,5 +119,15 @@
             android:indeterminateOnly="true"
             android:importantForAccessibility="no"
             android:visibility="gone"/>
+
+        <CheckBox
+            android:id="@+id/check_box"
+            android:layout_width="24dp"
+            android:layout_height="24dp"
+            android:layout_marginEnd="16dp"
+            android:layout_gravity="right|center"
+            android:button="@drawable/ic_circle_check_box"
+            android:visibility="gone"
+        />
     </FrameLayout>
 </LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/media_session_view.xml b/packages/SystemUI/res/layout/media_session_view.xml
new file mode 100644
index 0000000..cc02fea
--- /dev/null
+++ b/packages/SystemUI/res/layout/media_session_view.xml
@@ -0,0 +1,313 @@
+<?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.
+  -->
+
+<!-- Layout for media session-based controls -->
+<com.android.systemui.util.animation.TransitionLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/qs_media_controls"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:clipChildren="false"
+    android:clipToPadding="false"
+    android:gravity="center_horizontal|fill_vertical"
+    android:forceHasOverlappingRendering="false"
+    android:background="@drawable/qs_media_background"
+    android:theme="@style/MediaPlayer">
+
+    <androidx.constraintlayout.widget.Guideline
+        android:id="@+id/center_vertical_guideline"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        app:layout_constraintGuide_percent="0.6" />
+
+    <!-- App icon -->
+    <com.android.internal.widget.CachingIconView
+        android:id="@+id/icon"
+        android:layout_width="24dp"
+        android:layout_height="24dp"
+        android:layout_marginStart="@dimen/qs_media_padding"
+        android:layout_marginTop="@dimen/qs_media_padding"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
+    <!-- Seamless Output Switcher -->
+    <LinearLayout
+        android:id="@+id/media_seamless"
+        android:orientation="horizontal"
+        android:gravity="top|end"
+        android:paddingTop="@dimen/qs_media_padding"
+        android:paddingEnd="@dimen/qs_media_padding"
+        android:background="@drawable/qs_media_light_source"
+        android:forceHasOverlappingRendering="false"
+        android:layout_width="wrap_content"
+        android:layout_height="48dp"
+        android:layout_marginStart="@dimen/qs_center_guideline_padding"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintStart_toEndOf="@id/center_vertical_guideline"
+        app:layout_constraintHorizontal_bias="1"
+        app:layout_constrainedWidth="true"
+        app:layout_constraintWidth_min="@dimen/min_clickable_item_size"
+        app:layout_constraintHeight_min="@dimen/min_clickable_item_size">
+        <LinearLayout
+            android:id="@+id/media_seamless_button"
+            android:layout_width="wrap_content"
+            android:layout_height="@dimen/qs_seamless_height"
+            android:minHeight="@dimen/qs_seamless_height"
+            android:theme="@style/MediaPlayer.SolidButton"
+            android:background="@drawable/qs_media_seamless_background"
+            android:orientation="horizontal"
+            android:contentDescription="@string/quick_settings_media_device_label">
+            <ImageView
+                android:id="@+id/media_seamless_image"
+                android:layout_width="@dimen/qs_seamless_icon_size"
+                android:layout_height="@dimen/qs_seamless_icon_size"
+                android:layout_gravity="center"
+                android:tint="?android:attr/textColorPrimary"
+                android:src="@*android:drawable/ic_media_seamless" />
+            <TextView
+                android:id="@+id/media_seamless_text"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center_vertical"
+                android:layout_marginStart="4dp"
+                android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
+                android:singleLine="true"
+                android:text="@*android:string/ext_media_seamless_action"
+                android:textDirection="locale"
+                android:textSize="12sp"
+                android:lineHeight="16sp" />
+        </LinearLayout>
+    </LinearLayout>
+
+    <!-- Song name -->
+    <TextView
+        android:id="@+id/header_title"
+        android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
+        android:singleLine="true"
+        android:textSize="16sp"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="20dp"
+        android:layout_marginStart="@dimen/qs_media_padding"
+        android:layout_marginEnd="@dimen/qs_media_padding"
+        app:layout_constrainedWidth="true"
+        app:layout_constraintTop_toBottomOf="@id/icon"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toStartOf="@id/actionPlayPause"
+        app:layout_constraintHorizontal_bias="0" />
+
+    <!-- Artist name -->
+    <TextView
+        android:id="@+id/header_artist"
+        android:fontFamily="@*android:string/config_headlineFontFamily"
+        android:singleLine="true"
+        style="@style/MediaPlayer.Subtitle"
+        android:textSize="14sp"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginEnd="@dimen/qs_media_padding"
+        app:layout_constrainedWidth="true"
+        android:layout_marginTop="1dp"
+        app:layout_constraintTop_toBottomOf="@id/header_title"
+        app:layout_constraintStart_toStartOf="@id/header_title"
+        app:layout_constraintEnd_toStartOf="@id/actionPlayPause"
+        app:layout_constraintBottom_toBottomOf="@id/actionPlayPause"
+        app:layout_constraintHorizontal_bias="0" />
+
+    <ImageButton
+        android:id="@+id/actionPlayPause"
+        style="@style/MediaPlayer.SessionAction.Primary"
+        android:layout_width="48dp"
+        android:layout_height="48dp"
+        android:layout_marginStart="@dimen/qs_media_padding"
+        android:layout_marginEnd="@dimen/qs_media_padding"
+        android:layout_marginTop="0dp"
+        android:layout_marginBottom="0dp"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/media_seamless"
+        app:layout_constraintBottom_toTopOf="@id/actionEnd" />
+
+    <ImageButton
+        android:id="@+id/actionPrev"
+        style="@style/MediaPlayer.SessionAction"
+        android:layout_width="48dp"
+        android:layout_height="48dp"
+        android:layout_marginStart="4dp"
+        android:layout_marginEnd="0dp"
+        android:layout_marginBottom="0dp"
+        android:layout_marginTop="0dp"
+        app:layout_constraintHorizontal_chainStyle="packed"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toStartOf="@id/media_progress_bar"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/actionPlayPause" />
+
+    <!-- Seek Bar -->
+    <!-- As per Material Design on Bidirectionality, this is forced to LTR in code -->
+    <SeekBar
+        android:id="@+id/media_progress_bar"
+        style="@style/MediaPlayer.ProgressBar"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:paddingTop="@dimen/qs_media_session_enabled_seekbar_vertical_padding"
+        android:paddingBottom="12dp"
+        android:maxHeight="@dimen/qs_media_enabled_seekbar_height"
+        android:splitTrack="false"
+        android:layout_marginBottom="0dp"
+        android:layout_marginTop="0dp"
+        android:layout_marginStart="0dp"
+        android:layout_marginEnd="0dp"
+        app:layout_constraintStart_toEndOf="@id/actionPrev"
+        app:layout_constraintEnd_toStartOf="@id/actionNext"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/actionPlayPause" />
+
+    <ImageButton
+        android:id="@+id/actionNext"
+        style="@style/MediaPlayer.SessionAction"
+        android:layout_width="48dp"
+        android:layout_height="48dp"
+        android:layout_marginStart="0dp"
+        android:layout_marginEnd="@dimen/qs_media_action_spacing"
+        android:layout_marginBottom="0dp"
+        android:layout_marginTop="0dp"
+        app:layout_constraintStart_toEndOf="@id/media_progress_bar"
+        app:layout_constraintEnd_toStartOf="@id/actionStart"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/actionPlayPause" />
+
+    <ImageButton
+        android:id="@+id/actionStart"
+        style="@style/MediaPlayer.SessionAction"
+        android:layout_width="48dp"
+        android:layout_height="48dp"
+        android:layout_marginStart="@dimen/qs_media_action_spacing"
+        android:layout_marginEnd="@dimen/qs_media_action_spacing"
+        android:layout_marginBottom="0dp"
+        android:layout_marginTop="0dp"
+        app:layout_constraintStart_toEndOf="@id/actionNext"
+        app:layout_constraintEnd_toStartOf="@id/actionEnd"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/actionPlayPause" />
+
+    <ImageButton
+        android:id="@+id/actionEnd"
+        style="@style/MediaPlayer.SessionAction"
+        android:layout_width="48dp"
+        android:layout_height="48dp"
+        android:layout_marginStart="@dimen/qs_media_action_spacing"
+        android:layout_marginEnd="4dp"
+        android:layout_marginBottom="0dp"
+        android:layout_marginTop="0dp"
+        app:layout_constraintHorizontal_chainStyle="packed"
+        app:layout_constraintStart_toEndOf="@id/actionStart"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/actionPlayPause" />
+
+    <!-- Long press menu -->
+    <TextView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="@dimen/qs_media_padding"
+        android:layout_marginStart="@dimen/qs_media_padding"
+        android:layout_marginEnd="@dimen/qs_media_padding"
+        android:id="@+id/remove_text"
+        android:fontFamily="@*android:string/config_headlineFontFamily"
+        android:singleLine="true"
+        android:ellipsize="marquee"
+        android:marqueeRepeatLimit="marquee_forever"
+        android:text="@string/controls_media_close_session"
+        android:gravity="center_horizontal|top"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintBottom_toTopOf="@id/cancel" />
+
+    <FrameLayout
+        android:id="@+id/settings"
+        android:background="@drawable/qs_media_light_source"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="@dimen/qs_media_padding"
+        android:layout_marginEnd="@dimen/qs_media_action_spacing"
+        android:layout_marginBottom="@dimen/qs_media_padding"
+        app:layout_constrainedWidth="true"
+        app:layout_constraintWidth_min="@dimen/min_clickable_item_size"
+        app:layout_constraintHeight_min="@dimen/min_clickable_item_size"
+        app:layout_constraintHorizontal_chainStyle="spread_inside"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toStartOf="@id/cancel"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/remove_text">
+        <TextView
+            android:id="@+id/settings_text"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center|bottom"
+            style="@style/MediaPlayer.OutlineButton"
+            android:text="@string/controls_media_settings_button" />
+    </FrameLayout>
+
+    <FrameLayout
+        android:id="@+id/cancel"
+        android:background="@drawable/qs_media_light_source"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="@dimen/qs_media_action_spacing"
+        android:layout_marginEnd="@dimen/qs_media_action_spacing"
+        android:layout_marginBottom="@dimen/qs_media_padding"
+        app:layout_constrainedWidth="true"
+        app:layout_constraintWidth_min="@dimen/min_clickable_item_size"
+        app:layout_constraintHeight_min="@dimen/min_clickable_item_size"
+        app:layout_constraintStart_toEndOf="@id/settings"
+        app:layout_constraintEnd_toStartOf="@id/dismiss"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/remove_text">
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center|bottom"
+            style="@style/MediaPlayer.OutlineButton"
+            android:text="@string/cancel" />
+    </FrameLayout>
+
+    <FrameLayout
+        android:id="@+id/dismiss"
+        android:background="@drawable/qs_media_light_source"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="@dimen/qs_media_action_spacing"
+        android:layout_marginEnd="@dimen/qs_media_padding"
+        android:layout_marginBottom="@dimen/qs_media_padding"
+        app:layout_constrainedWidth="true"
+        app:layout_constraintWidth_min="@dimen/min_clickable_item_size"
+        app:layout_constraintHeight_min="@dimen/min_clickable_item_size"
+        app:layout_constraintStart_toEndOf="@id/cancel"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/remove_text">
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center|bottom"
+            style="@style/MediaPlayer.OutlineButton"
+            android:text="@string/controls_media_dismiss_button" />
+    </FrameLayout>
+</com.android.systemui.util.animation.TransitionLayout>
diff --git a/packages/SystemUI/res/layout/media_ttt_chip.xml b/packages/SystemUI/res/layout/media_ttt_chip.xml
index 6fbc41c..2d082dc 100644
--- a/packages/SystemUI/res/layout/media_ttt_chip.xml
+++ b/packages/SystemUI/res/layout/media_ttt_chip.xml
@@ -26,6 +26,13 @@
     android:gravity="center_vertical"
     >
 
+    <com.android.internal.widget.CachingIconView
+        android:id="@+id/app_icon"
+        android:layout_width="@dimen/media_ttt_icon_size"
+        android:layout_height="@dimen/media_ttt_icon_size"
+        android:layout_marginEnd="12dp"
+        />
+
     <TextView
         android:id="@+id/text"
         android:layout_width="wrap_content"
@@ -37,8 +44,8 @@
     <ProgressBar
         android:id="@+id/loading"
         android:indeterminate="true"
-        android:layout_width="@dimen/media_ttt_icon_size"
-        android:layout_height="@dimen/media_ttt_icon_size"
+        android:layout_width="@dimen/media_ttt_loading_size"
+        android:layout_height="@dimen/media_ttt_loading_size"
         android:layout_marginStart="12dp"
         android:indeterminateTint="?androidprv:attr/colorAccentPrimaryVariant"
         style="?android:attr/progressBarStyleSmall"
diff --git a/packages/SystemUI/res/layout/media_ttt_chip_receiver.xml b/packages/SystemUI/res/layout/media_ttt_chip_receiver.xml
new file mode 100644
index 0000000..88feacd
--- /dev/null
+++ b/packages/SystemUI/res/layout/media_ttt_chip_receiver.xml
@@ -0,0 +1,32 @@
+<?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.
+  -->
+<!-- TODO(b/203800646): layout_marginTop doesn't seem to work on some large screens. -->
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:background="@drawable/media_ttt_chip_background_receiver"
+    >
+
+    <com.android.internal.widget.CachingIconView
+        android:id="@+id/app_icon"
+        android:layout_width="@dimen/media_ttt_icon_size_receiver"
+        android:layout_height="@dimen/media_ttt_icon_size_receiver"
+        android:layout_gravity="center"
+        />
+
+</FrameLayout>
diff --git a/packages/SystemUI/res/layout/qs_paged_tile_layout.xml b/packages/SystemUI/res/layout/qs_paged_tile_layout.xml
index 6b054a9..619591d 100644
--- a/packages/SystemUI/res/layout/qs_paged_tile_layout.xml
+++ b/packages/SystemUI/res/layout/qs_paged_tile_layout.xml
@@ -20,4 +20,6 @@
     android:id="@+id/qs_pager"
     android:layout_width="match_parent"
     android:layout_height="0dp"
-    android:layout_weight="1"/>
+    android:layout_weight="1"
+    android:clipChildren="false"
+    android:clipToPadding="false" />
diff --git a/packages/SystemUI/res/layout/super_notification_shade.xml b/packages/SystemUI/res/layout/super_notification_shade.xml
index b28cb2f..60860ba 100644
--- a/packages/SystemUI/res/layout/super_notification_shade.xml
+++ b/packages/SystemUI/res/layout/super_notification_shade.xml
@@ -101,7 +101,10 @@
         <FrameLayout android:id="@+id/keyguard_bouncer_container"
                      android:layout_height="0dp"
                      android:layout_width="match_parent"
-                     android:layout_weight="1" />
+                     android:layout_weight="1"
+                     android:background="@android:color/transparent"
+                     android:clipChildren="false"
+                     android:clipToPadding="false" />
     </LinearLayout>
 
     <com.android.systemui.biometrics.AuthRippleView
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index f2754aa..f083b85 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Geen toestelle beskikbaar nie"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi-Fi is nie gekoppel nie"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Helderheid"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Keer kleure om"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Kleuromkering"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"Meer instellings"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Gebruikerinstellings"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"Klaar"</string>
@@ -747,7 +747,7 @@
     <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Vergroot die hele skerm"</string>
     <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Vergroot \'n deel van die skerm"</string>
     <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Wissel"</string>
-    <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Toeganklikheidknoppie het die toeganklikheidgebaar vervang\n\n"<annotation id="link">"Bekyk instellings"</annotation></string>
+    <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Tik om toeganklikheidkenmerke oop te maak Pasmaak of vervang knoppie in Instellings.\n\n"<annotation id="link">"Bekyk instellings"</annotation></string>
     <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Skuif knoppie na kant om dit tydelik te versteek"</string>
     <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Beweeg na links bo"</string>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Beweeg na regs bo"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Instellings"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> deur <xliff:g id="ARTIST_NAME">%2$s</xliff:g> speel tans vanaf <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> van <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"Speel"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"Onderbreek"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"Vorige snit"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"Volgende snit"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Speel"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Maak <xliff:g id="APP_LABEL">%1$s</xliff:g> oop"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Speel <xliff:g id="SONG_NAME">%1$s</xliff:g> deur <xliff:g id="ARTIST_NAME">%2$s</xliff:g> vanaf <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Speel <xliff:g id="SONG_NAME">%1$s</xliff:g> vanaf <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"Ontdoen"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Beweeg nader om op <xliff:g id="DEVICENAME">%1$s</xliff:g> te speel"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"Speel tans op <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Onaktief, gaan program na"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Nie gekry nie"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrole is nie beskikbaar nie"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 toestel gekies"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> toestelle gekies"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(ontkoppel)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Kon nie koppel nie. Probeer weer."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Kan nie wissel nie. Tik om weer te probeer."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Bind nuwe toestel saam"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Bounommer"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Bounommer is na knipbord gekopieer."</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"Sien alles"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Ontkoppel Ethernet om netwerke te wissel"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Om toestelervaring te verbeter, kan programme en dienste steeds enige tyd na wi‑fi-netwerke soek, selfs wanneer wi‑fi af is. Jy kan dit in Wi-fi-opsporing-instellings verander. "<annotation id="link">"Verander"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Skakel vliegtuigmodus af"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Kies gebruiker"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Programme wat op die agtergrond werk"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Stop"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-af/tiles_states_strings.xml b/packages/SystemUI/res/values-af/tiles_states_strings.xml
index a9e1a23..2059490 100644
--- a/packages/SystemUI/res/values-af/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-af/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"Af"</item>
     <item msgid="460891964396502657">"Aan"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"Onbeskikbaar"</item>
+    <item msgid="5581384648880018330">"Af"</item>
+    <item msgid="8000850843692192257">"Aan"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index e463894..839b8d2 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"ምንም መሣሪያዎች አይገኙም"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi-Fi አልተገናኘም"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"ብሩህነት"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"ቀለማትን ግልብጥ"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"ተቃራኒ ቀለም"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"ተጨማሪ ቅንብሮች"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"የተጠቃሚ ቅንብሮች"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"ተከናውኗል"</string>
@@ -747,7 +747,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="5217151214439341902">"የተደራሽነት ባህሪያትን ለመክፈት መታ ያድርጉ። ይህንን አዝራር በቅንብሮች ውስጥ ያብጁ ወይም ይተኩ።\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>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"ወደ ላይኛው ቀኝ አንቀሳቅስ"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"ቅንብሮች"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> በ<xliff:g id="ARTIST_NAME">%2$s</xliff:g> ከ<xliff:g id="APP_LABEL">%3$s</xliff:g> እየተጫወተ ነው"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> ከ<xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"አጫውት"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"ላፍታ አቁም"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"ቀዳሚ ትራክ"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"ቀጣይ ትራክ"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"አጫውት"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> ክፈት"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="SONG_NAME">%1$s</xliff:g> በ<xliff:g id="ARTIST_NAME">%2$s</xliff:g> ከ<xliff:g id="APP_LABEL">%3$s</xliff:g> ያጫውቱ"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="SONG_NAME">%1$s</xliff:g> ከ<xliff:g id="APP_LABEL">%2$s</xliff:g> ያጫውቱ"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"ቀልብስ"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"በ<xliff:g id="DEVICENAME">%1$s</xliff:g> ላይ ለማጫወት ጠጋ ያድርጉ"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"በ<xliff:g id="DEVICENAME">%1$s</xliff:g> ላይ በማጫወት ላይ"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"ንቁ ያልኾነ፣ መተግበሪያን ይፈትሹ"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"አልተገኘም"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"መቆጣጠሪያ አይገኝም"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 መሣሪያ ተመርጧል"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> መሣሪያዎች ተመርጠዋል"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(ተቋርጧል)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"ማገናኘት አልተቻለም። እንደገና ይሞክሩ።"</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"መቀየር አይቻልም። እንደገና ለመሞከር መታ ያድርጉ።"</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"አዲስ መሣሪያ ያጣምሩ"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"የግንብ ቁጥር"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"የገንባ ቁጥር ወደ ቅንጥብ ሰሌዳ ተቀድቷል።"</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"ሁሉንም ይመልከቱ"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"አውታረ መረቦችን ለመቀየር፣ የኢተርኔት ግንኙነት ያቋርጡ"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"የመሣሪያ ተሞክሮን ለማሻሻል፣ መተግበሪያዎች እና አገልግሎቶች አሁንም በማንኛውም ጊዜ የWi-Fi አውታረ መረቦችን መቃኘት ይችላሉ፣ Wi-Fi ጠፍቶ ቢሆንም እንኳ። ይህንን በ Wi‑Fi ቅኝት ቅንብሮች ውስጥ መቀየር ይችላሉ። "<annotation id="link">"ቀይር"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"የአውሮፕላን ሁነታን ያጥፉ"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"ተጠቃሚን ይምረጡ"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"ከበስተጀርባ የሚሠሩ መተግበሪያዎች"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"መቆሚያ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-am/tiles_states_strings.xml b/packages/SystemUI/res/values-am/tiles_states_strings.xml
index 2b0062a..7fdfd11 100644
--- a/packages/SystemUI/res/values-am/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-am/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"አጥፋ"</item>
     <item msgid="460891964396502657">"አብራ"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"አይገኝም"</item>
+    <item msgid="5581384648880018330">"አጥፋ"</item>
+    <item msgid="8000850843692192257">"አብራ"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 6f73bed..6110793 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -222,7 +222,7 @@
     <string name="accessibility_rotation_lock_on_landscape" msgid="936972553861524360">"تم قفل الشاشة في الاتجاه الأفقي."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="2356633398683813837">"تم قفل الشاشة في الاتجاه العمودي."</string>
     <string name="dessert_case" msgid="9104973640704357717">"حالة الحلويات"</string>
-    <string name="start_dreams" msgid="9131802557946276718">"شاشة التوقف"</string>
+    <string name="start_dreams" msgid="9131802557946276718">"شاشة الاستراحة"</string>
     <string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
     <string name="quick_settings_dnd_label" msgid="7728690179108024338">"عدم الإزعاج"</string>
     <string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"بلوتوث"</string>
@@ -254,7 +254,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"لا يتوفر أي جهاز"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"‏لم يتم الاتصال بشبكة Wi-Fi."</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"السطوع"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"قلب الألوان"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"قلب الألوان"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"المزيد من الإعدادات"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"إعدادات المستخدم"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"تم"</string>
@@ -767,7 +767,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="5217151214439341902">"انقر لفتح ميزات تسهيل الاستخدام. يمكنك تخصيص هذا الزر أو استبداله من الإعدادات.\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>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"نقل إلى أعلى يسار الشاشة"</string>
@@ -822,10 +822,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"الإعدادات"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"يتم تشغيل <xliff:g id="SONG_NAME">%1$s</xliff:g> للفنان <xliff:g id="ARTIST_NAME">%2$s</xliff:g> من تطبيق <xliff:g id="APP_LABEL">%3$s</xliff:g>."</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> من إجمالي <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"تشغيل"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"إيقاف مؤقت"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"المقطع الصوتي السابق"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"المقطع الصوتي التالي"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"تشغيل"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"فتح <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"تشغيل <xliff:g id="SONG_NAME">%1$s</xliff:g> للفنان <xliff:g id="ARTIST_NAME">%2$s</xliff:g> من تطبيق <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"تشغيل <xliff:g id="SONG_NAME">%1$s</xliff:g> من تطبيق <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"تراجع"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"عليك الاقتراب لتشغيل الموسيقى على <xliff:g id="DEVICENAME">%1$s</xliff:g>."</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"جارٍ تشغيل الموسيقى على <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"غير نشط، تحقّق من التطبيق."</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"لم يتم العثور عليه."</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"عنصر التحكّم غير متوفّر"</string>
@@ -840,7 +847,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"تم اختيار جهاز واحد."</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"تم اختيار <xliff:g id="COUNT">%1$d</xliff:g> جهاز."</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(غير متّصل)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"تعذّر الاتصال. يُرجى إعادة المحاولة."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"لا يمكن التبديل. انقر لإعادة المحاولة."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"إقران جهاز جديد"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"رقم الإصدار"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"تم نسخ رقم الإصدار إلى الحافظة."</string>
@@ -905,8 +912,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"عرض الكل"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"للتبديل بين الشبكات، يجب فصل إيثرنت."</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"‏لتحسين تجربتك على الجهاز، يظل بإمكان التطبيقات والخدمات البحث عن شبكات Wi‑Fi في أي وقت، حتى عند إيقاف شبكة Wi‑Fi. وبإمكانك تغيير هذا الخيار في إعدادات البحث عن شبكات Wi-Fi. "<annotation id="link">"تغيير"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"إيقاف وضع الطيران"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"اختيار المستخدم"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"التطبيقات التي يتم تشغيلها في الخلفية"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"إيقاف"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ar/tiles_states_strings.xml b/packages/SystemUI/res/values-ar/tiles_states_strings.xml
index 4facf293d..d7026c7 100644
--- a/packages/SystemUI/res/values-ar/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ar/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"غير مفعّل"</item>
     <item msgid="460891964396502657">"مفعّل"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"غير متوفّر"</item>
+    <item msgid="5581384648880018330">"غير مفعّل"</item>
+    <item msgid="8000850843692192257">"مفعّل"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 679231f..3fe47cb 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"কোনো ডিভাইচ নাই"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"ৱাই-ফাইৰ সৈতে সংযোগ হৈ থকা নাই"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"উজ্জ্বলতা"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"ৰং ওলোটা কৰক"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"ৰং বিপৰীতকৰণ"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"অধিক ছেটিং"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"ব্যৱহাৰকাৰীৰ ছেটিং"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"সম্পন্ন কৰা হ’ল"</string>
@@ -747,7 +747,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="5217151214439341902">"সাধ্য সুবিধাসমূহ খুলিবলৈ টিপক। ছেটিঙত এই বুটামটো কাষ্টমাইজ অথবা সলনি কৰক।\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>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"শীৰ্ষৰ সোঁফালে নিয়ক"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"ছেটিং"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g>ত <xliff:g id="ARTIST_NAME">%2$s</xliff:g>ৰ <xliff:g id="SONG_NAME">%1$s</xliff:g> গীতটো প্লে’ হৈ আছে"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="TOTAL_TIME">%2$s</xliff:g>ৰ <xliff:g id="ELAPSED_TIME">%1$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"প্লে’ কৰক"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"পজ কৰক"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"পূৰ্বৱৰ্তী ট্ৰেক"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"পৰৱৰ্তী ট্ৰেক"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"প্লে’ কৰক"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> খোলক"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="APP_LABEL">%3$s</xliff:g>ত <xliff:g id="ARTIST_NAME">%2$s</xliff:g>ৰ <xliff:g id="SONG_NAME">%1$s</xliff:g> গীতটো প্লে’ কৰক"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="APP_LABEL">%2$s</xliff:g>ত <xliff:g id="SONG_NAME">%1$s</xliff:g> গীতটো প্লে’ কৰক"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"আনডু কৰক"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"<xliff:g id="DEVICENAME">%1$s</xliff:g>ত প্লে\' কৰিবলৈ ওপৰলৈ যাওক"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"<xliff:g id="DEVICENAME">%1$s</xliff:g>ত প্লে\' কৰি থকা হৈছে"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"সক্ৰিয় নহয়, এপ্‌টো পৰীক্ষা কৰক"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"বিচাৰি পোৱা নগ’ল"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"নিয়ন্ত্ৰণটো উপলব্ধ নহয়"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"১ টা ডিভাইচ বাছনি কৰা হৈছে"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> টা ডিভাইচ বাছনি কৰা হৈছে"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(সংযোগ বিচ্ছিন্ন কৰা হৈছে)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"সংযোগ কৰিব পৰা নগ’ল। পুনৰ চেষ্টা কৰক।"</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"সলনি কৰিব নোৱাৰি। আকৌ চেষ্টা কৰিবলৈ টিপক।"</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"নতুন ডিভাইচ পেয়াৰ কৰক"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"বিল্ডৰ নম্বৰ"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"ক্লিপব’ৰ্ডলৈ বিল্ডৰ নম্বৰ প্ৰতিলিপি কৰা হ’ল।"</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"আটাইবোৰ চাওক"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"নেটৱৰ্ক সলনি কৰিবলৈ ইথাৰনেটৰ পৰা সংযোগ বিচ্ছিন্ন কৰক"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"ডিভাইচ ব্যৱহাৰৰ অভিজ্ঞতা উন্নত কৰিবলৈ ৱাই-ফাই অফ থকা অৱস্থাতো এপ্ আৰু সেৱাসমূহে ৱাই-ফাই নেটৱৰ্কবোৰ স্কেন কৰিব পাৰে। আপুনি ৱাই-ফাই স্কেনিঙৰ ছেটিঙত এইটো সলনি কৰিব পাৰে। "<annotation id="link">"সলনি কৰক"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"এয়াৰপ্লে’ন ম’ডটো অফ কৰক"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"ব্যৱহাৰকাৰী বাছনি কৰক"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"নেপথ্যত চলি থকা এপ্"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"বন্ধ কৰক"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-as/tiles_states_strings.xml b/packages/SystemUI/res/values-as/tiles_states_strings.xml
index 69a2efc..efb2351 100644
--- a/packages/SystemUI/res/values-as/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-as/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"অফ"</item>
     <item msgid="460891964396502657">"অন"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"উপলব্ধ নহয়"</item>
+    <item msgid="5581384648880018330">"অফ আছে"</item>
+    <item msgid="8000850843692192257">"অন আছে"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index a7fe41d..255ce58 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Heç bir cihaz əlçatan deyil"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi-Fi qoşulu deyil"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Parlaqlıq"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Rəng inversiyası"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Rəng inversiyası"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"Digər ayarlar"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"İstifadəçi ayarları"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"Hazır"</string>
@@ -747,7 +747,7 @@
     <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Tam ekranı böyüdün"</string>
     <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Ekran hissəsinin böyüdülməsi"</string>
     <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Dəyişdirici"</string>
-    <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Jest xüsusi imkanlar düyməsinə dəyişdirildi\n\n"<annotation id="link">"Ayarlara baxın"</annotation></string>
+    <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Əlçatımlılıq funksiyalarını açmaq üçün toxunun. Ayarlarda bu düyməni fərdiləşdirin və ya dəyişdirin.\n\n"<annotation id="link">"Ayarlara baxın"</annotation></string>
     <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Düyməni müvəqqəti gizlətmək üçün kənara çəkin"</string>
     <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Yuxarıya sola köçürün"</string>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Yuxarıya sağa köçürün"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Ayarlar"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> tərəfindən <xliff:g id="SONG_NAME">%1$s</xliff:g> <xliff:g id="APP_LABEL">%3$s</xliff:g> tətbiqindən oxudulur"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g>/<xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"Oxudun"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"Durdurun"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"Əvvəlki trek"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"Növbəti trek"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Oxudun"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> tətbiqini açın"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> tərəfindən <xliff:g id="SONG_NAME">%1$s</xliff:g> mahnısını <xliff:g id="APP_LABEL">%3$s</xliff:g> tətbiqindən oxudun"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="SONG_NAME">%1$s</xliff:g> mahnısını <xliff:g id="APP_LABEL">%2$s</xliff:g> tətbiqindən oxudun"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"Geri qaytarın"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"<xliff:g id="DEVICENAME">%1$s</xliff:g> cihazında oxutmaq üçün yaxınlaşın"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"<xliff:g id="DEVICENAME">%1$s</xliff:g> cihazında oxudulur"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Aktiv deyil, tətbiqi yoxlayın"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Tapılmadı"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Nəzarət əlçatan deyil"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 cihaz seçilib"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> cihaz seçilib"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(bağlantı kəsildi)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Qoşulmaq alınmadı. Yenə cəhd edin."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Dəyişmək olmur. Yenidən cəhd etmək üçün toxunun."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Cihaz əlavə edin"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Montaj nömrəsi"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Versiya nömrəsi mübadilə buferinə kopyalandı."</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"Hamısına baxın"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Şəbəkəni dəyişmək üçün etherneti ayırın"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Cihaz təcrübəsini yaxşılaşdırmaq üçün Wi-Fi deaktiv olduqda belə, tətbiqlər və xidmətlər Wi-Fi şəbəkəsini axtara biləcək. Bunu Wi-Fi axtarışı ayarlarında dəyişə bilərsiniz. "<annotation id="link">"Dəyişin"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Təyyarə rejimini deaktiv edin"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"İstifadəçi seçin"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Arxa fonda işləyən tətbiqlər"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Dayandırın"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-az/tiles_states_strings.xml b/packages/SystemUI/res/values-az/tiles_states_strings.xml
index d46175bd..7c47203 100644
--- a/packages/SystemUI/res/values-az/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-az/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"Deaktiv"</item>
     <item msgid="460891964396502657">"Aktiv"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"Əlçatmazdır"</item>
+    <item msgid="5581384648880018330">"Deaktiv"</item>
+    <item msgid="8000850843692192257">"Aktiv"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index bebec60..f29d9de 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -251,7 +251,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Nije dostupan nijedan uređaj"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"WiFi nije povezan"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Osvetljenost"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Obrni boje"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inverzija boja"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"Još podešavanja"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Korisnička podešavanja"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"Gotovo"</string>
@@ -752,7 +752,7 @@
     <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Uvećajte ceo ekran"</string>
     <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Uvećajte deo ekrana"</string>
     <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Pređi"</string>
-    <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Dugme Pristupačnost je zamenilo pokret za pristupačnost\n\n"<annotation id="link">"Prikaži podešavanja"</annotation></string>
+    <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Dodirnite za funkcije pristupačnosti. Prilagodite ili zamenite ovo dugme u Podešavanjima.\n\n"<annotation id="link">"Podešavanja"</annotation></string>
     <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Pomerite dugme do ivice da biste ga privremeno sakrili"</string>
     <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Premesti gore levo"</string>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Premesti gore desno"</string>
@@ -804,10 +804,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Podešavanja"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> izvođača <xliff:g id="ARTIST_NAME">%2$s</xliff:g> se pušta iz aplikacije <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> od <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"Pusti"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"Pauziraj"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"Prethodna pesma"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"Sledeća pesma"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Pusti"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Otvorite <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Pustite <xliff:g id="SONG_NAME">%1$s</xliff:g> izvođača <xliff:g id="ARTIST_NAME">%2$s</xliff:g> iz aplikacije <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Pustite <xliff:g id="SONG_NAME">%1$s</xliff:g> iz aplikacije <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"Opozovi"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Približite da biste puštali muziku na: <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"Pušta se na: <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Neaktivno. Vidite aplikaciju"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Nije pronađeno"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrola nije dostupna"</string>
@@ -822,7 +829,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"Izabran je 1 uređaj"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"Izabranih uređaja: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(veza je prekinuta)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Povezivanje nije uspelo. Probajte ponovo."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Prebacivanje nije uspelo. Probajte ponovo."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Upari novi uređaj"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Broj verzije"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Broj verzije je kopiran u privremenu memoriju."</string>
@@ -887,8 +894,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"Pogledajte sve"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Da biste promenili mrežu, prekinite eternet vezu"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Radi boljeg doživljaja uređaja, aplikacije i usluge i dalje mogu da traže WiFi mreže u bilo kom trenutku, čak i kada je WiFi isključen. To možete da promenite u podešavanjima WiFi skeniranja. "<annotation id="link">"Promenite"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Isključite režim rada u avionu"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Izaberite korisnika"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Aplikacije pokrenute u pozadini"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Zaustavi"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/tiles_states_strings.xml b/packages/SystemUI/res/values-b+sr+Latn/tiles_states_strings.xml
index 5d9edf5..88caf97 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"Isključeno"</item>
     <item msgid="460891964396502657">"Uključeno"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"Nedostupno"</item>
+    <item msgid="5581384648880018330">"Isključeno"</item>
+    <item msgid="8000850843692192257">"Uključeno"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 98a4e22..3b0c1a3 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -252,7 +252,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Няма даступных прылад"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Няма падключэння да Wi-Fi"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Яркасць"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Інвертаваць колеры"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Інверсія колераў"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"Дадатковыя налады"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Налады карыстальніка"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"Гатова"</string>
@@ -757,7 +757,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="5217151214439341902">"Націсніце, каб адкрыць спецыяльныя магчымасці. Рэгулюйце ці замяняйце кнопку ў Наладах.\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>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Перамясціць правей і вышэй"</string>
@@ -810,10 +810,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Налады"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"У праграме \"<xliff:g id="APP_LABEL">%3$s</xliff:g>\" прайграецца кампазіцыя \"<xliff:g id="SONG_NAME">%1$s</xliff:g>\", выканаўца – <xliff:g id="ARTIST_NAME">%2$s</xliff:g>"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> з <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"Прайграць"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"Прыпыніць"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"Папярэдні трэк"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"Наступны трэк"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Прайграць"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Адкрыйце праграму \"<xliff:g id="APP_LABEL">%1$s</xliff:g>\""</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Прайграйце кампазіцыю \"<xliff:g id="SONG_NAME">%1$s</xliff:g>\" (выканаўца – <xliff:g id="ARTIST_NAME">%2$s</xliff:g>) з дапамогай праграмы \"<xliff:g id="APP_LABEL">%3$s</xliff:g>\""</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Прайграйце кампазіцыю \"<xliff:g id="SONG_NAME">%1$s</xliff:g>\" з дапамогай праграмы \"<xliff:g id="APP_LABEL">%2$s</xliff:g>\""</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"Адрабіць"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Наблізьцеся, каб прайграць музыку на прыладзе \"<xliff:g id="DEVICENAME">%1$s</xliff:g>\""</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"Прайграецца на прыладзе \"<xliff:g id="DEVICENAME">%1$s</xliff:g>\""</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Неактыўна, праверце праграму"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Не знойдзена"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Кіраванне недаступнае"</string>
@@ -828,7 +835,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"Выбрана 1 прылада"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"Выбрана прылад: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(адключана)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Не ўдалося падключыцца. Паўтарыце спробу."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Не ўдалося пераключыцца. Дакраніцеся, каб паўтарыць спробу."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Спалучыць з новай прыладай"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Нумар зборкі"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Нумар зборкі скапіраваны ў буфер абмену."</string>
@@ -893,8 +900,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"Паказаць усе"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Каб падключыцца да сетак, выключыце Ethernet"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Каб палепшыць працу прылады, вы можаце дазволіць праграмам і сэрвісам шукаць сеткі Wi-Fi, нават калі Wi‑Fi выключаны. Змяніць гэты рэжым можна ў наладах пошуку сетак Wi-Fi. "<annotation id="link">"Змяніць"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Выключыць рэжым палёту"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Выбар карыстальніка"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Праграмы працуюць у фонавым рэжыме"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Спыніць"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-be/tiles_states_strings.xml b/packages/SystemUI/res/values-be/tiles_states_strings.xml
index 72b9bc6..ecfde0b 100644
--- a/packages/SystemUI/res/values-be/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-be/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"Выключана"</item>
     <item msgid="460891964396502657">"Уключана"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"Недаступна"</item>
+    <item msgid="5581384648880018330">"Выключана"</item>
+    <item msgid="8000850843692192257">"Уключана"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index ea68193..6881fcf 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Няма налични устройства"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"не е установена връзка с Wi-Fi"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Яркост"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Инвертиране на цветовете"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Инвертиране на цветовете"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"Още настройки"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Потребителски настройки"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"Готово"</string>
@@ -747,7 +747,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="5217151214439341902">"Докоснете, за да отворите функциите за достъпност. Персон./заменете бутона от настройките.\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>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Преместване горе вдясно"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Настройки"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> на <xliff:g id="ARTIST_NAME">%2$s</xliff:g> се възпроизвежда от <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> от <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"Пускане"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"Пауза"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"Предишен запис"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"Следващ запис"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Google Play"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Отваряне на <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Пускане на <xliff:g id="SONG_NAME">%1$s</xliff:g> на <xliff:g id="ARTIST_NAME">%2$s</xliff:g> от <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Пускане на <xliff:g id="SONG_NAME">%1$s</xliff:g> от <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"Отмяна"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Преместете се по-близо, за да се възпроизведе на <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"Възпроизвежда се на <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Неактивно, проверете прилож."</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Не е намерено"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Контролата не е налице"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 избрано устройство"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> избрани устройства"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(връзката е прекратена)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Неуспешно свързване. Опитайте отново."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Не може да се превключи. Докоснете за нов опит."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Сдвояване на ново устройство"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Номер на компилацията"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Номерът на компилацията е копиран в буферната памет."</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"Вижте всички"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"За да превключите мрежите, прекъснете връзката с Ethernet"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"С цел подобряване на практическата работа с устройството приложенията и услугите пак могат да сканират за Wi‑Fi мрежи по всяко време дори когато функцията за Wi‑Fi e изключена. Можете да промените съответното поведение от настройките за сканиране за Wi‑Fi. "<annotation id="link">"Промяна"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Изключване на самолетния режим"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Избор на потребител"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Приложения, които се изпълняват на заден план"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Спиране"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-bg/tiles_states_strings.xml b/packages/SystemUI/res/values-bg/tiles_states_strings.xml
index f0747cc..7424f81 100644
--- a/packages/SystemUI/res/values-bg/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-bg/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"Изкл."</item>
     <item msgid="460891964396502657">"Вкл."</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"Не е налице"</item>
+    <item msgid="5581384648880018330">"Изкл."</item>
+    <item msgid="8000850843692192257">"Вкл."</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 377bd47..571118a 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"কোনো ডিভাইস উপলব্ধ নয়"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"ওয়াই-ফাই কানেক্ট করা নেই"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"উজ্জ্বলতা"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"বিপরীত রঙ"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"কালার ইনভার্সন"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"আরও সেটিংস"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"ব্যবহারকারী সেটিংস"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"সম্পন্ন হয়েছে"</string>
@@ -747,7 +747,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="5217151214439341902">"অ্যাক্সেসিবিলিটি ফিচার খুলতে ট্যাপ করুন। কাস্টমাইজ করুন বা সেটিংসে এই বোতামটি সরিয়ে দিন।\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>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"উপরে ডানদিকে সরান"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"সেটিংস"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g>-এর <xliff:g id="SONG_NAME">%1$s</xliff:g> গানটি <xliff:g id="APP_LABEL">%3$s</xliff:g> অ্যাপে চলছে"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="TOTAL_TIME">%2$s</xliff:g>টির মধ্যে <xliff:g id="ELAPSED_TIME">%1$s</xliff:g>টি"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"চালান"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"পজ করুন"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"আগের ট্র্যাক"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"পরের ট্র্যাক"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"চালান"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> অ্যাপ খুলুন"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g>-এর <xliff:g id="SONG_NAME">%1$s</xliff:g> গানটি <xliff:g id="APP_LABEL">%3$s</xliff:g> অ্যাপে চালান"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="SONG_NAME">%1$s</xliff:g> গানটি <xliff:g id="APP_LABEL">%2$s</xliff:g> অ্যাপে চালান"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"আগের অবস্থায় ফিরুন"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"<xliff:g id="DEVICENAME">%1$s</xliff:g>-এ চালাতে আরও কাছে আনুন"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"<xliff:g id="DEVICENAME">%1$s</xliff:g>-এ ভিডিও চালানো হচ্ছে"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"বন্ধ আছে, অ্যাপ চেক করুন"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"খুঁজে পাওয়া যায়নি"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"কন্ট্রোল উপলভ্য নেই"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"১টি ডিভাইস বেছে নেওয়া হয়েছে"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g>টি ডিভাইস বেছে নেওয়া হয়েছে"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(ডিসকানেক্ট হয়ে গেছে)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"কানেক্ট করা যায়নি। আবার চেষ্টা করুন।"</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"পাল্টানো যাচ্ছে না। আবার চেষ্টা করতে ট্যাপ করুন।"</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"নতুন ডিভাইস পেয়ার করুন"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"বিল্ড নম্বর"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"বিল্ড নম্বর ক্লিপবোর্ডে কপি করা হয়েছে।"</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"সবকটি দেখুন"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"নেটওয়ার্ক বদলাতে ইথারনেট ডিসকানেক্ট করুন"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"ডিভাইস সংক্রান্ত অভিজ্ঞতা আরও ভাল করতে, অ্যাপ ও পরিষেবা যেকোনও সময় আপনার ওয়াই-ফাই নেটওয়ার্ক স্ক্যান করতে পারবে, এমনকি ডিভাইসের ওয়াই-ফাই বন্ধ করা থাকলেও। ওয়াই-ফাই স্ক্যানিং সেটিংস থেকে আপনি এটি পরিবর্তন করতে পারবেন। "<annotation id="link">"পরিবর্তন করুন"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"\'বিমান\' মোড বন্ধ করুন"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"ব্যবহারকারী বেছে নিন"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"ব্যাকগ্রাউন্ডে অ্যাপ চলছে"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"বন্ধ করুন"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-bn/tiles_states_strings.xml b/packages/SystemUI/res/values-bn/tiles_states_strings.xml
index 0530e46..eddf851 100644
--- a/packages/SystemUI/res/values-bn/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-bn/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"বন্ধ আছে"</item>
     <item msgid="460891964396502657">"চালু আছে"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"উপলভ্য নেই"</item>
+    <item msgid="5581384648880018330">"বন্ধ আছে"</item>
+    <item msgid="8000850843692192257">"চালু আছে"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 23eeb77..6d4326b 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -251,7 +251,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Nema dostupnih uređaja"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"WiFi mreža nije povezana"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Osvjetljenje"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Inverzija boja"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inverzija boja"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"Više postavki"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Korisničke postavke"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"Gotovo"</string>
@@ -752,7 +752,7 @@
     <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Uvećavanje prikaza preko cijelog ekrana"</string>
     <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Uvećavanje dijela ekrana"</string>
     <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Prekidač"</string>
-    <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Dugme za pristupačnost je zamijenilo pokret za pristupačnost\n\n"<annotation id="link">"Prikaži postavke"</annotation></string>
+    <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Dodirnite da otvorite funkcije pristupačnosti. Prilagodite ili zamijenite dugme u Postavkama.\n\n"<annotation id="link">"Postavke"</annotation></string>
     <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Premjestite dugme do ivice da ga privremeno sakrijete"</string>
     <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Pomjeranje gore lijevo"</string>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Pomjeranje gore desno"</string>
@@ -804,10 +804,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Postavke"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"Pjesma <xliff:g id="SONG_NAME">%1$s</xliff:g> izvođača <xliff:g id="ARTIST_NAME">%2$s</xliff:g> se reproducira pomoću aplikacije <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> od <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"Reproduciranje"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"Pauziranje"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"Prethodna numera"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"Sljedeća numera"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Pokrenite"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Otvorite aplikaciju <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Reproducirajte pjesmu <xliff:g id="SONG_NAME">%1$s</xliff:g> izvođača <xliff:g id="ARTIST_NAME">%2$s</xliff:g> pomoću aplikacije <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Reproducirajte pjesmu <xliff:g id="SONG_NAME">%1$s</xliff:g> pomoću aplikacije <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"Poništi"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Približite se da reproducirate na uređaju <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"Reproducira se na uređaju <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Neaktivno, vidite aplikaciju"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Nije pronađeno"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrola nije dostupna"</string>
@@ -822,7 +829,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"Odabran je 1 uređaj"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"Broj odabranih uređaja: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(veza je prekinuta)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Povezivanje nije uspjelo. Pokušajte ponovo."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Nije moguće prebaciti. Dodirnite da pokušate ponovo."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Uparite novi uređaj"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Broj verzije"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Broj verzije je kopiran u međumemoriju."</string>
@@ -887,8 +894,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"Prikaži sve"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Da promijenite mrežu, isključite ethernet"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Radi poboljšanja iskustva s uređajem aplikacije i usluge i dalje mogu bilo kada skenirati WiFi mreže, čak i kada je WiFi isključen. Ovo možete promijeniti u Postavkama skeniranja WiFi mreže. "<annotation id="link">"Promijeni"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Isključi način rada u avionu"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Odaberite korisnika"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Aplikacije su aktivne u pozadini"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Zaustavi"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-bs/tiles_states_strings.xml b/packages/SystemUI/res/values-bs/tiles_states_strings.xml
index 5d9edf5..88caf97 100644
--- a/packages/SystemUI/res/values-bs/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-bs/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"Isključeno"</item>
     <item msgid="460891964396502657">"Uključeno"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"Nedostupno"</item>
+    <item msgid="5581384648880018330">"Isključeno"</item>
+    <item msgid="8000850843692192257">"Uključeno"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 446b0f4..e6c7cfb 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"No hi ha cap dispositiu disponible."</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"La Wi‑Fi no està connectada"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Brillantor"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Inverteix colors"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inversió de colors"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"Més opcions"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Configuració d\'usuari"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"Fet"</string>
@@ -747,7 +747,7 @@
     <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Amplia la pantalla completa"</string>
     <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Amplia una part de la pantalla"</string>
     <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Canvia"</string>
-    <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"El gest d\'accessibilitat s\'ha substituït pel botó d\'accessibilitat\n\n"<annotation id="link">"Mostra la configuració"</annotation></string>
+    <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Toca per obrir funcions d\'accessibilitat. Personalitza o substitueix el botó a Configuració.\n\n"<annotation id="link">"Mostra"</annotation>"."</string>
     <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Mou el botó a l\'extrem per amagar-lo temporalment"</string>
     <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Mou a dalt a l\'esquerra"</string>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Mou a dalt a la dreta"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Configuració"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> (<xliff:g id="ARTIST_NAME">%2$s</xliff:g>) s\'està reproduint des de l\'aplicació <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> de <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"Reprodueix"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"Posa en pausa"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"Pista anterior"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"Pista següent"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Reprodueix"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Obre <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Reprodueix <xliff:g id="SONG_NAME">%1$s</xliff:g> (<xliff:g id="ARTIST_NAME">%2$s</xliff:g>) des de l\'aplicació <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Reprodueix <xliff:g id="SONG_NAME">%1$s</xliff:g> des de l\'aplicació <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"Desfés"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Mou més a prop per reproduir a <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"S\'està reproduint a <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Inactiu; comprova l\'aplicació"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"No s\'ha trobat"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"El control no està disponible"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 dispositiu seleccionat"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"S\'han seleccionat <xliff:g id="COUNT">%1$d</xliff:g> dispositius"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(desconnectat)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"No s\'ha pogut connectar. Torna-ho a provar."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"No es pot canviar. Torna-ho a provar."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Vincula un dispositiu nou"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Número de compilació"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"El número de compilació s\'ha copiat al porta-retalls."</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"Mostra-ho tot"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Per canviar de xarxa, desconnecta la connexió Ethernet"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Per millorar l\'experiència del dispositiu, les aplicacions i els serveis poden cercar xarxes Wi‑Fi en qualsevol moment, fins i tot quan la Wi‑Fi estigui desactivada. Pots canviar aquesta opció a la configuració de cerca de xarxes Wi‑Fi. "<annotation id="link">"Canvia-la"</annotation>"."</string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Desactiva el mode d\'avió"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Selecciona un usuari"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Aplicacions que s\'executen en segon pla"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Atura"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ca/tiles_states_strings.xml b/packages/SystemUI/res/values-ca/tiles_states_strings.xml
index 55dfec0..e3538fa 100644
--- a/packages/SystemUI/res/values-ca/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ca/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"Desactivat"</item>
     <item msgid="460891964396502657">"Activat"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"No disponible"</item>
+    <item msgid="5581384648880018330">"Desactivat"</item>
+    <item msgid="8000850843692192257">"Activat"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 37a827b..b2becd8 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -252,7 +252,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Nejsou dostupná žádná zařízení"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Není připojena Wi-Fi"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Jas"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Převrátit barvy"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Převrácení barev"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"Další nastavení"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Uživatelské nastavení"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"Hotovo"</string>
@@ -757,7 +757,7 @@
     <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Zvětšit celou obrazovku"</string>
     <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Zvětšit část obrazovky"</string>
     <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Přepnout"</string>
-    <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Tlačítko přístupnosti bylo nahrazeno gestem přístupnosti\n\n"<annotation id="link">"Zobrazit nastavení"</annotation></string>
+    <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Klepnutím otevřete funkce přístupnosti. Tlačítko lze upravit nebo nahradit v Nastavení.\n\n"<annotation id="link">"Nastavení"</annotation></string>
     <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Přesunutím tlačítka k okraji ho dočasně skryjete"</string>
     <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Přesunout vlevo nahoru"</string>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Přesunout vpravo nahoru"</string>
@@ -810,10 +810,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Nastavení"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"Skladba <xliff:g id="SONG_NAME">%1$s</xliff:g> od interpreta <xliff:g id="ARTIST_NAME">%2$s</xliff:g> hrajte z aplikace <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> z <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"Přehrát"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"Pozastavit"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"Předchozí skladba"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"Další skladba"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Přehrát"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Otevřít aplikaci <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Přehrát skladbu <xliff:g id="SONG_NAME">%1$s</xliff:g> od interpreta <xliff:g id="ARTIST_NAME">%2$s</xliff:g> z aplikace <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Přehrát skladbu <xliff:g id="SONG_NAME">%1$s</xliff:g> z aplikace <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"Vrátit zpět"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Pokud chcete přehrávat na zařízení <xliff:g id="DEVICENAME">%1$s</xliff:g>, přibližte se k němu"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"Přehrává se na zařízení <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Neaktivní, zkontrolujte aplikaci"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Nenalezeno"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Ovládání není k dispozici"</string>
@@ -828,7 +835,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"Je vybráno 1 zařízení"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"Vybraná zařízení: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(odpojeno)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Spojení se nezdařilo. Zkuste to znovu."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Nelze přepnout. Klepnutím opakujte akci."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Spárovat nové zařízení"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Číslo sestavení"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Číslo sestavení bylo zkopírováno do schránky."</string>
@@ -893,8 +900,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"Zobrazit vše"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Pokud chcete přepnout sítě, odpojte ethernet"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Za účelem lepšího fungování zařízení mohou aplikace a služby vyhledávat sítě Wi-Fi, i když je připojení Wi-Fi vypnuté. Toto chování můžete změnit v nastavení vyhledávání Wi-Fi. "<annotation id="link">"Změnit"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Vypnout režim Letadlo"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Zvolte uživatele"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Aplikace běžící na pozadí"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Konec"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-cs/tiles_states_strings.xml b/packages/SystemUI/res/values-cs/tiles_states_strings.xml
index 30f5bef..3f40ab6 100644
--- a/packages/SystemUI/res/values-cs/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-cs/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"Vypnuto"</item>
     <item msgid="460891964396502657">"Zapnuto"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"Nedostupné"</item>
+    <item msgid="5581384648880018330">"Vyp"</item>
+    <item msgid="8000850843692192257">"Zap"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index bb4553f..d559c15 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Der er ingen tilgængelige enheder"</string>
     <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_inversion_label" msgid="5078769633069667698">"Ombyt farver"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Ombytning af farver"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"Flere indstillinger"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Brugerindstillinger"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"Udfør"</string>
@@ -747,7 +747,7 @@
     <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Forstør hele skærmen"</string>
     <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Forstør en del af skærmen"</string>
     <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Skift"</string>
-    <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Knappen Hjælpefunktioner har erstattet bevægelsen for hjælpefunktioner\n\n"<annotation id="link">"Se indstillinger"</annotation></string>
+    <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Tryk for at åbne hjælpefunktioner. Tilpas eller erstat denne knap i Indstillinger.\n\n"<annotation id="link">"Se indstillingerne"</annotation></string>
     <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Flyt knappen til kanten for at skjule den midlertidigt"</string>
     <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Flyt op til venstre"</string>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Flyt op til højre"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Indstillinger"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> af <xliff:g id="ARTIST_NAME">%2$s</xliff:g> afspilles via <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> af <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"Afspil"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"Sæt på pause"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"Afspil forrige"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"Næste nummer"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Afspil"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Åbn <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Afspil <xliff:g id="SONG_NAME">%1$s</xliff:g> af <xliff:g id="ARTIST_NAME">%2$s</xliff:g> via <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Afspil <xliff:g id="SONG_NAME">%1$s</xliff:g> via <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"Fortryd"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Flyt enheden tættere på for at afspille på <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"Afspilles på <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Inaktiv. Tjek appen"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Ikke fundet"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Styringselement ikke tilgængeligt"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"Der er valgt 1 enhed"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"Der er valgt <xliff:g id="COUNT">%1$d</xliff:g> enhed"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(afbrudt)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Der kunne ikke oprettes forbindelse. Prøv igen."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Det var ikke muligt at skifte. Tryk for at prøve igen."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Par ny enhed"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Buildnummer"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Buildnummeret blev kopieret til udklipsholderen."</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"Se alle"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Afbryd ethernetforbindelsen for at skifte netværk"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"For at forbedre brugeroplevelsen på enheden kan apps og tjenester stadig til enhver tid scanne efter Wi‑Fi-netværk, også selvom Wi‑Fi er deaktiveret. Du kan ændre dette i indstillingerne for Wi-Fi-scanning. "<annotation id="link">"Skift indstilling"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Deaktiver flytilstand"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Vælg bruger"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Apps, der kører i baggrunden"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Stop"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-da/tiles_states_strings.xml b/packages/SystemUI/res/values-da/tiles_states_strings.xml
index 0423949..b479a44 100644
--- a/packages/SystemUI/res/values-da/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-da/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"Fra"</item>
     <item msgid="460891964396502657">"Til"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"Ikke tilgængelig"</item>
+    <item msgid="5581384648880018330">"Fra"</item>
+    <item msgid="8000850843692192257">"Til"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 13ad7aa..801d9e0 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -181,7 +181,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="6327378061894076288">"Der Flugmodus ist aktiviert."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"lautlos"</string>
     <string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"nur Weckrufe"</string>
-    <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"Nicht stören."</string>
+    <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"Bitte nicht stören."</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="1457150026842505799">"„Bitte nicht stören“ deaktiviert."</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="186315911607486129">"„Bitte nicht stören“ aktiviert"</string>
     <string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth."</string>
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Keine Geräte verfügbar"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"WLAN nicht verbunden"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Helligkeit"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Farben umkehren"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Farbumkehr"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"Weitere Einstellungen"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Nutzereinstellungen"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"Fertig"</string>
@@ -747,7 +747,7 @@
     <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Ganzen Bildschirm vergrößern"</string>
     <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Teil des Bildschirms vergrößern"</string>
     <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Schalter"</string>
-    <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Die Schaltfläche „Bedienungshilfen“ ersetzt die Touch-Geste für Bedienungshilfen\n\n"<annotation id="link">"Einstellungen aufrufen"</annotation></string>
+    <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Tippe, um die Bedienungshilfen aufzurufen. Du kannst diese Schaltfläche in den Einstellungen anpassen oder ersetzen.\n\n"<annotation id="link">"Zu den Einstellungen"</annotation></string>
     <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Durch Ziehen an den Rand wird die Schaltfläche zeitweise ausgeblendet"</string>
     <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Nach oben links verschieben"</string>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Nach rechts oben verschieben"</string>
@@ -798,10 +798,17 @@
     <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>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> von <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"Wiedergeben"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"Pausieren"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"Vorheriger Titel"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"Nächster Titel"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Wiedergeben"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> öffnen"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="SONG_NAME">%1$s</xliff:g> von <xliff:g id="ARTIST_NAME">%2$s</xliff:g> über <xliff:g id="APP_LABEL">%3$s</xliff:g> wiedergeben"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="SONG_NAME">%1$s</xliff:g> über <xliff:g id="APP_LABEL">%2$s</xliff:g> wiedergeben"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"Rückgängig machen"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Gehe für die Wiedergabe näher an <xliff:g id="DEVICENAME">%1$s</xliff:g> heran"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"Wird auf <xliff:g id="DEVICENAME">%1$s</xliff:g> abgespielt"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Inaktiv – sieh in der App nach"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Nicht gefunden"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Steuerelement nicht verfügbar"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"Ein Gerät ausgewählt"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> Geräte ausgewählt"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(nicht verbunden)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Verbindung nicht möglich. Versuch es noch einmal."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Wechseln nicht möglich. Tippe, um es noch einmal zu versuchen."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Neues Gerät koppeln"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Build-Nummer"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Build-Nummer in Zwischenablage kopiert."</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"Alle ansehen"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Trenne das Ethernetkabel, um das Netzwerk zu wechseln"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Zur Verbesserung der Gerätenutzung können Apps und Dienste weiter nach WLANs suchen, auch wenn die WLAN-Funktion deaktiviert ist. Dies lässt sich in den Einstellungen für die WLAN-Suche ändern. "<annotation id="link">"Ändern"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Flugmodus deaktivieren"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Nutzer auswählen"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Apps, die im Hintergrund ausgeführt werden"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Beenden"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-de/tiles_states_strings.xml b/packages/SystemUI/res/values-de/tiles_states_strings.xml
index a67ce6c..81f030c 100644
--- a/packages/SystemUI/res/values-de/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-de/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"Aus"</item>
     <item msgid="460891964396502657">"An"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"Nicht verfügbar"</item>
+    <item msgid="5581384648880018330">"Aus"</item>
+    <item msgid="8000850843692192257">"An"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 38534f4..bc7d3b0 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Δεν υπάρχουν διαθέσιμες συσκευές"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Το Wi-Fi δεν είναι συνδεδεμένο"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Φωτεινότητα"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Αντιστροφή χρωμάτων"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Αντιστροφή χρωμάτων"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"Περισσότερες ρυθμίσεις"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Ρυθμίσεις χρήστη"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"Τέλος"</string>
@@ -747,7 +747,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="5217151214439341902">"Πατήστε για άνοιγμα των λειτουργιών προσβασιμότητας. Προσαρμόστε ή αντικαταστήστε το κουμπί στις Ρυθμίσεις.\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>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Μετακίνηση επάνω δεξιά"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Ρυθμίσεις"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"Γίνεται αναπαραγωγή του <xliff:g id="SONG_NAME">%1$s</xliff:g> από <xliff:g id="ARTIST_NAME">%2$s</xliff:g> στην εφαρμογή <xliff:g id="APP_LABEL">%3$s</xliff:g>."</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> από <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"Αναπαραγωγή"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"Παύση"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"Προηγούμενο κομμάτι"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"Επόμενο κομμάτι"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Play"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Άνοιγμα της εφαρμογής <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Αναπαραγωγή του <xliff:g id="SONG_NAME">%1$s</xliff:g> από <xliff:g id="ARTIST_NAME">%2$s</xliff:g> στην εφαρμογή <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Αναπαραγωγή του <xliff:g id="SONG_NAME">%1$s</xliff:g> στην εφαρμογή <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"Αναίρεση"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Πλησιάστε για αναπαραγωγή στη συσκευή <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"Αναπαραγωγή στη συσκευή <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Ανενεργό, έλεγχος εφαρμογής"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Δεν βρέθηκε."</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Μη διαθέσιμο στοιχείο ελέγχου"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"Επιλέχτηκε 1 συσκευή"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"Επιλέχτηκαν <xliff:g id="COUNT">%1$d</xliff:g> συσκευές"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(αποσυνδέθηκε)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Δεν ήταν δυνατή η σύνδεση. Δοκιμάστε ξανά."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Δεν είναι δυνατή η εναλλαγή. Πατήστε για επανάληψη."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Σύζευξη νέας συσκευής"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Αριθμός έκδοσης"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Ο αριθμός έκδοσης αντιγράφηκε στο πρόχειρο."</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"Εμφάνιση όλων"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Για εναλλαγή δικτύων, αποσυνδέστε το ethernet"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Για βελτίωση της εμπειρίας στη συσκευή, οι εφαρμογές και οι υπηρεσίες μπορούν ακόμα να εκτελούν σάρωση για δίκτυα Wi‑Fi ανά πάσα στιγμή, ακόμα και όταν το Wi‑Fi είναι απενεργοποιημένο. Μπορείτε να αλλάξετε αυτήν τη ρύθμιση στις ρυθμίσεις της Σάρωσης Wi‑Fi. "<annotation id="link">"Αλλαγή"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Απενεργοποίηση λειτουργίας πτήσης"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Επιλογή χρήστη"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Οι εφαρμογές βρίσκονται σε εξέλιξη στο παρασκήνιο"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Διακοπή"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-el/tiles_states_strings.xml b/packages/SystemUI/res/values-el/tiles_states_strings.xml
index 55d162d..422f2aa 100644
--- a/packages/SystemUI/res/values-el/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-el/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"Ανενεργή"</item>
     <item msgid="460891964396502657">"Ενεργή"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"Μη διαθέσιμο"</item>
+    <item msgid="5581384648880018330">"Ανενεργό"</item>
+    <item msgid="8000850843692192257">"Ενεργό"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 8debf42..3427442 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"No devices available"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi‑Fi not connected"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Brightness"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Invert colours"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Colour inversion"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"More settings"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"User settings"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"Done"</string>
@@ -747,7 +747,7 @@
     <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Magnify full screen"</string>
     <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Magnify part of screen"</string>
     <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Switch"</string>
-    <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Accessibility button replaced the accessibility gesture\n\n"<annotation id="link">"View settings"</annotation></string>
+    <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Tap to open accessibility features. Customise or replace this button in Settings.\n\n"<annotation id="link">"View settings"</annotation></string>
     <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Move button to the edge to hide it temporarily"</string>
     <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Move top left"</string>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Move top right"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Settings"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> by <xliff:g id="ARTIST_NAME">%2$s</xliff:g> is playing from <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> of <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"Play"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"Pause"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"Previous track"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"Next track"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Play"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Open <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Play <xliff:g id="SONG_NAME">%1$s</xliff:g> by <xliff:g id="ARTIST_NAME">%2$s</xliff:g> from <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Play <xliff:g id="SONG_NAME">%1$s</xliff:g> from <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"Undo"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Move closer to play on <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"Playing on <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Inactive, check app"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Not found"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Control is unavailable"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"One device selected"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> devices selected"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(disconnected)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Couldn\'t connect. Try again."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Can\'t switch. Tap to try again."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Pair new device"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Build number"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Build number copied to clipboard."</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"See all"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"To switch networks, disconnect Ethernet"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"To improve device experience, apps and services can still scan for Wi‑Fi networks at any time, even when Wi‑Fi is off. You can change this in Wi‑Fi scanning settings. "<annotation id="link">"Change"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Turn off aeroplane mode"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Select user"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Apps running in the background"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Stop"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rAU/tiles_states_strings.xml b/packages/SystemUI/res/values-en-rAU/tiles_states_strings.xml
index fea1f10..9b00c8b 100644
--- a/packages/SystemUI/res/values-en-rAU/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"Off"</item>
     <item msgid="460891964396502657">"On"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"Unavailable"</item>
+    <item msgid="5581384648880018330">"Off"</item>
+    <item msgid="8000850843692192257">"On"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index da144d8..b6d1b1d 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"No devices available"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi‑Fi not connected"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Brightness"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Invert colours"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Colour inversion"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"More settings"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"User settings"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"Done"</string>
@@ -747,7 +747,7 @@
     <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Magnify full screen"</string>
     <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Magnify part of screen"</string>
     <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Switch"</string>
-    <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Accessibility button replaced the accessibility gesture\n\n"<annotation id="link">"View settings"</annotation></string>
+    <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Tap to open accessibility features. Customise or replace this button in Settings.\n\n"<annotation id="link">"View settings"</annotation></string>
     <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Move button to the edge to hide it temporarily"</string>
     <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Move top left"</string>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Move top right"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Settings"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> by <xliff:g id="ARTIST_NAME">%2$s</xliff:g> is playing from <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> of <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"Play"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"Pause"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"Previous track"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"Next track"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Play"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Open <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Play <xliff:g id="SONG_NAME">%1$s</xliff:g> by <xliff:g id="ARTIST_NAME">%2$s</xliff:g> from <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Play <xliff:g id="SONG_NAME">%1$s</xliff:g> from <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"Undo"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Move closer to play on <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"Playing on <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Inactive, check app"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Not found"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Control is unavailable"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"One device selected"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> devices selected"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(disconnected)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Couldn\'t connect. Try again."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Can\'t switch. Tap to try again."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Pair new device"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Build number"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Build number copied to clipboard."</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"See all"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"To switch networks, disconnect Ethernet"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"To improve device experience, apps and services can still scan for Wi‑Fi networks at any time, even when Wi‑Fi is off. You can change this in Wi‑Fi scanning settings. "<annotation id="link">"Change"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Turn off aeroplane mode"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Select user"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Apps running in the background"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Stop"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rCA/tiles_states_strings.xml b/packages/SystemUI/res/values-en-rCA/tiles_states_strings.xml
index fea1f10..9b00c8b 100644
--- a/packages/SystemUI/res/values-en-rCA/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"Off"</item>
     <item msgid="460891964396502657">"On"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"Unavailable"</item>
+    <item msgid="5581384648880018330">"Off"</item>
+    <item msgid="8000850843692192257">"On"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 8debf42..3427442 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"No devices available"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi‑Fi not connected"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Brightness"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Invert colours"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Colour inversion"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"More settings"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"User settings"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"Done"</string>
@@ -747,7 +747,7 @@
     <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Magnify full screen"</string>
     <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Magnify part of screen"</string>
     <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Switch"</string>
-    <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Accessibility button replaced the accessibility gesture\n\n"<annotation id="link">"View settings"</annotation></string>
+    <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Tap to open accessibility features. Customise or replace this button in Settings.\n\n"<annotation id="link">"View settings"</annotation></string>
     <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Move button to the edge to hide it temporarily"</string>
     <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Move top left"</string>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Move top right"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Settings"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> by <xliff:g id="ARTIST_NAME">%2$s</xliff:g> is playing from <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> of <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"Play"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"Pause"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"Previous track"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"Next track"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Play"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Open <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Play <xliff:g id="SONG_NAME">%1$s</xliff:g> by <xliff:g id="ARTIST_NAME">%2$s</xliff:g> from <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Play <xliff:g id="SONG_NAME">%1$s</xliff:g> from <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"Undo"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Move closer to play on <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"Playing on <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Inactive, check app"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Not found"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Control is unavailable"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"One device selected"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> devices selected"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(disconnected)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Couldn\'t connect. Try again."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Can\'t switch. Tap to try again."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Pair new device"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Build number"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Build number copied to clipboard."</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"See all"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"To switch networks, disconnect Ethernet"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"To improve device experience, apps and services can still scan for Wi‑Fi networks at any time, even when Wi‑Fi is off. You can change this in Wi‑Fi scanning settings. "<annotation id="link">"Change"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Turn off aeroplane mode"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Select user"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Apps running in the background"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Stop"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rGB/tiles_states_strings.xml b/packages/SystemUI/res/values-en-rGB/tiles_states_strings.xml
index fea1f10..9b00c8b 100644
--- a/packages/SystemUI/res/values-en-rGB/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"Off"</item>
     <item msgid="460891964396502657">"On"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"Unavailable"</item>
+    <item msgid="5581384648880018330">"Off"</item>
+    <item msgid="8000850843692192257">"On"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 8debf42..3427442 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"No devices available"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi‑Fi not connected"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Brightness"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Invert colours"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Colour inversion"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"More settings"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"User settings"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"Done"</string>
@@ -747,7 +747,7 @@
     <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Magnify full screen"</string>
     <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Magnify part of screen"</string>
     <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Switch"</string>
-    <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Accessibility button replaced the accessibility gesture\n\n"<annotation id="link">"View settings"</annotation></string>
+    <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Tap to open accessibility features. Customise or replace this button in Settings.\n\n"<annotation id="link">"View settings"</annotation></string>
     <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Move button to the edge to hide it temporarily"</string>
     <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Move top left"</string>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Move top right"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Settings"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> by <xliff:g id="ARTIST_NAME">%2$s</xliff:g> is playing from <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> of <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"Play"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"Pause"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"Previous track"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"Next track"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Play"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Open <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Play <xliff:g id="SONG_NAME">%1$s</xliff:g> by <xliff:g id="ARTIST_NAME">%2$s</xliff:g> from <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Play <xliff:g id="SONG_NAME">%1$s</xliff:g> from <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"Undo"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Move closer to play on <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"Playing on <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Inactive, check app"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Not found"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Control is unavailable"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"One device selected"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> devices selected"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(disconnected)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Couldn\'t connect. Try again."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Can\'t switch. Tap to try again."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Pair new device"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Build number"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Build number copied to clipboard."</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"See all"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"To switch networks, disconnect Ethernet"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"To improve device experience, apps and services can still scan for Wi‑Fi networks at any time, even when Wi‑Fi is off. You can change this in Wi‑Fi scanning settings. "<annotation id="link">"Change"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Turn off aeroplane mode"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Select user"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Apps running in the background"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Stop"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rIN/tiles_states_strings.xml b/packages/SystemUI/res/values-en-rIN/tiles_states_strings.xml
index fea1f10..9b00c8b 100644
--- a/packages/SystemUI/res/values-en-rIN/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"Off"</item>
     <item msgid="460891964396502657">"On"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"Unavailable"</item>
+    <item msgid="5581384648880018330">"Off"</item>
+    <item msgid="8000850843692192257">"On"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index bb95d28..a4e9ab4 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‏‏‎‎‎‎‎‎‎‎‎‎‎‎‏‏‎‏‎‏‎‎‏‏‏‎‏‎‎‎‏‏‎‏‏‎‎‎‎‏‎‏‎‎‏‏‏‎‎‏‎‏‏‏‎‎‏‎No devices available‎‏‎‎‏‎"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‎‏‏‏‏‎‏‎‏‎‎‎‏‎‎‎‏‎‏‎‎‏‎‎‎‏‎‏‎‎‏‎‏‎‏‎‏‏‏‏‏‎‎‎‎‎‏‏‎‏‏‎‏‏‎Wi‑Fi not connected‎‏‎‎‏‎"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‎‎‎‏‏‏‏‎‏‏‏‎‎‏‎‎‏‏‏‏‎‎‏‎‎‎‏‎‏‏‎‏‏‎‎‏‏‎‏‎‏‏‎‎‏‏‎‏‎‎‎‏‎‏‎‎‎Brightness‎‏‎‎‏‎"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‎‎‏‏‏‏‎‏‏‎‏‏‎‏‎‏‎‎‎‎‏‎‎‏‎‏‎‏‎‎‎‏‏‎‎‏‎‏‎‎‎‏‎‎‏‎‏‎‏‎‏‏‏‎‎‏‎‎Invert colors‎‏‎‎‏‎"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‎‎‏‎‎‏‎‏‏‏‏‏‏‎‏‏‎‎‏‏‏‎‏‏‏‏‏‎‏‎‏‏‏‏‏‏‎‎‏‏‏‎‏‏‎‏‎‎‎‏‎‏‏‎‏‎‎‎‎Color inversion‎‏‎‎‏‎"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‏‏‏‏‏‎‎‎‏‏‎‎‎‏‏‎‎‎‏‎‏‎‎‏‏‎‏‏‎‏‎‎‏‏‏‏‎‏‏‎‏‎‎‎‏‎‏‎‎‎‎‏‏‎‏‏‎‎More settings‎‏‎‎‏‎"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‎‏‏‎‎‎‏‎‎‏‏‎‎‎‎‎‎‏‏‎‏‏‎‎‏‎‎‏‏‎‏‎‏‎‏‎‎‏‎‏‏‏‎‎‏‎‏‏‎‎‎‎‎‎‎‏‎‎User settings‎‏‎‎‏‎"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‎‎‎‎‎‎‏‏‎‏‏‎‎‏‏‎‎‎‏‎‎‏‏‎‎‏‏‏‎‎‏‏‎‎‎‏‎‎‏‎‎‏‏‎‏‎‎‏‎‏‏‏‏‎‎‎‏‎Done‎‏‎‎‏‎"</string>
@@ -747,7 +747,7 @@
     <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‎‏‎‎‏‎‎‏‏‎‏‏‏‎‏‏‎‎‎‏‎‏‎‎‏‏‏‏‏‏‎‏‎‏‎‏‏‏‎‏‎‎‏‎‏‎‏‏‏‎‏‎‎‎‎‎‏‎Magnify full screen‎‏‎‎‏‎"</string>
     <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‎‏‏‏‏‎‎‎‎‏‎‎‏‎‎‏‎‎‎‎‎‏‎‏‎‏‎‏‏‎‏‏‏‏‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‏‎‏‎Magnify part of screen‎‏‎‎‏‎"</string>
     <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‎‏‎‏‎‏‎‏‎‏‎‎‏‎‏‎‏‎‏‎‏‎‎‏‏‏‎‎‏‏‎‏‏‏‎‎‎‎‎‏‎‎‎‏‏‎‎‎‏‏‏‎‏‎‏‏‏‎Switch‎‏‎‎‏‎"</string>
-    <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‏‎‏‏‏‏‏‏‎‎‎‏‏‏‏‎‏‏‎‏‎‎‏‎‎‎‎‏‏‏‎‎‎‏‏‏‏‎‏‎‏‏‏‎‏‏‏‎‎‏‏‎‎‎‏‎‎‎Accessibility button replaced the accessibility gesture‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎"<annotation id="link">"‎‏‎‎‏‏‏‎View settings‎‏‎‎‏‏‎"</annotation>"‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+    <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‎‎‏‏‎‎‏‏‏‎‎‎‎‏‎‏‏‎‏‏‎‎‎‏‏‎‏‎‎‏‏‎‎‎‎‏‎‎‏‏‏‏‎‎‏‏‏‏‏‎‏‎‎‏‏‏‎‎Tap to open accessibility features. Customize or replace this button in Settings.‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎"<annotation id="link">"‎‏‎‎‏‏‏‎View settings‎‏‎‎‏‏‎"</annotation>"‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‎‏‎‎‏‎‎‏‏‎‏‏‎‎‎‎‏‎‎‏‎‏‎‏‎‏‎‎‏‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‎‎‏‎‎‎‏‏‎‏‎Move button to the edge to hide it temporarily‎‏‎‎‏‎"</string>
     <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‎‏‏‎‎‏‎‎‎‏‏‏‏‎‏‏‏‏‏‏‏‎‎‏‎‏‎‎‎‎‏‏‎‏‎‏‏‏‎‏‏‏‏‏‏‏‎‎‎‎‎‏‎‏‎‎‏‎Move top left‎‏‎‎‏‎"</string>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‎‏‎‏‏‏‏‎‏‏‎‏‎‏‎‏‏‏‏‎‏‎‎‎‎‏‎‎‎‏‏‎‏‎‎‎‏‏‏‏‏‏‏‎‎‏‏‏‎‎‎‎‏‏‏‏‏‎Move top right‎‏‎‎‏‎"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‎‎‏‎‏‏‎‏‎‏‏‏‎‏‎‏‏‎‏‎‎‎‎‎‎‏‎‏‏‎‏‎‎‎‏‏‎‏‏‎‏‏‎‎‎‎‎‎‏‏‎‎‎‏‏‎‎‎‎Settings‎‏‎‎‏‎"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‎‏‏‏‎‎‏‎‎‎‏‏‎‎‎‎‎‏‎‎‏‎‎‏‏‎‏‏‏‎‏‏‎‎‏‏‎‎‏‎‏‎‎‎‏‏‏‏‎‏‎‏‏‏‎‏‎‎‎‏‎‎‏‏‎<xliff:g id="SONG_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ by ‎‏‎‎‏‏‎<xliff:g id="ARTIST_NAME">%2$s</xliff:g>‎‏‎‎‏‏‏‎ is playing from ‎‏‎‎‏‏‎<xliff:g id="APP_LABEL">%3$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‎‏‏‏‎‏‎‏‏‎‎‎‏‎‎‎‏‏‎‏‏‎‎‎‎‏‏‏‏‏‎‏‎‎‏‏‎‏‏‏‏‏‎‎‏‏‎‏‎‎‏‎‏‎‎‏‏‎‎‏‎‎‏‏‎<xliff:g id="ELAPSED_TIME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ of ‎‏‎‎‏‏‎<xliff:g id="TOTAL_TIME">%2$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‏‏‎‎‎‏‎‏‎‎‏‎‏‎‏‎‏‎‎‎‏‏‎‏‎‏‏‎‎‎‎‏‎‎‏‎‏‎‏‏‏‎‎‏‏‎‏‏‏‏‏‎‎‏‎‎‏‎Play‎‏‎‎‏‎"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‏‏‏‎‎‎‏‏‏‎‎‎‏‏‏‎‏‎‏‏‎‎‏‎‏‏‎‎‎‎‏‎‏‏‎‏‏‎‎‏‏‎‎‏‏‏‏‏‏‏‎‏‎‎‎‎‏‎‎Pause‎‏‎‎‏‎"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‎‎‏‎‎‎‎‏‎‎‎‏‎‏‏‏‏‎‎‎‎‎‏‏‏‏‎‎‏‏‏‏‎‏‏‏‏‎‎‏‎‎‏‏‎‎‏‎‎‏‏‎‏‎‎Previous track‎‏‎‎‏‎"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‎‎‏‏‏‎‏‏‎‎‏‏‏‎‎‎‎‏‎‏‏‎‏‏‎‎‏‏‎‏‎‏‏‎‎‏‏‎‎‎‎‏‏‎‏‎‎‎‎‏‏‎‏‏‎‏‎‎Next track‎‏‎‎‏‎"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‏‏‏‎‎‏‎‏‏‎‏‏‏‏‎‏‏‏‏‏‎‎‏‎‎‏‎‏‏‏‎‎‎‎‏‏‎‏‎‏‏‎‏‎‎‎‏‏‏‎‎‎‏‏‏‏‏‏‎Play‎‏‎‎‏‎"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‏‎‏‏‎‎‏‏‎‏‏‏‎‎‎‏‎‎‏‏‏‏‎‏‏‎‏‎‏‎‎‎‎‎‏‏‎‎‏‎‏‏‎‎‏‏‏‎‏‎‏‎‎‏‏‎‎‎Open ‎‏‎‎‏‏‎<xliff:g id="APP_LABEL">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‎‎‏‏‎‎‎‎‏‏‏‎‏‏‎‏‏‎‎‎‏‏‎‎‎‏‎‏‏‎‏‏‎‏‏‎‎‎‏‎‏‏‎‎‏‎‎‎‏‎‏‏‎‎‎‏‏‎Play ‎‏‎‎‏‏‎<xliff:g id="SONG_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ by ‎‏‎‎‏‏‎<xliff:g id="ARTIST_NAME">%2$s</xliff:g>‎‏‎‎‏‏‏‎ from ‎‏‎‎‏‏‎<xliff:g id="APP_LABEL">%3$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‎‎‏‏‎‎‏‎‎‏‎‏‏‏‎‎‏‏‏‎‎‎‏‎‏‏‏‎‏‎‏‏‏‎‏‎‎‏‎‎‎‏‎‎‏‎‎‏‏‏‏‏‏‎‎‏‎‏‎Play ‎‏‎‎‏‏‎<xliff:g id="SONG_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ from ‎‏‎‎‏‏‎<xliff:g id="APP_LABEL">%2$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‏‎‎‏‎‎‏‏‏‎‏‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‎‏‎‏‏‎‎‎‎‎‎‏‏‎‎‎‎‏‎‎‏‏‏‏‏‎‏‎‎‎‎‎‎Undo‎‏‎‎‏‎"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‏‎‏‎‎‏‏‎‎‏‎‏‎‏‎‏‎‏‏‎‎‏‏‎‎‏‎‎‎‏‏‏‏‏‎‏‎‏‏‎‏‏‎‏‏‎‎‎‏‏‎‏‏‏‎‏‎‏‎Move closer to play on ‎‏‎‎‏‏‎<xliff:g id="DEVICENAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‎‎‎‏‎‏‏‏‎‎‏‎‏‏‏‏‏‏‏‎‏‎‎‏‎‎‏‏‏‎‎‎‏‎‏‏‏‎‎‏‏‎‏‏‏‏‏‎‏‎‎‎‎‏‏‎‏‎Playing on ‎‏‎‎‏‏‎<xliff:g id="DEVICENAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‏‎‎‎‎‎‏‎‏‏‎‎‎‏‏‏‎‎‎‏‏‏‎‏‎‎‎‏‎‏‎‏‎‎‏‏‏‏‎‏‏‎‏‎‎‎‎‏‎‎‏‏‏‏‏‏‎‎Inactive, check app‎‏‎‎‏‎"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‎‏‎‏‎‎‏‎‎‏‎‏‎‎‎‎‏‎‏‏‏‎‏‎‎‏‎‎‏‏‎‏‎‎‎‏‏‏‏‏‎‏‏‏‏‏‎‎‏‏‎‎‏‏‏‏‎‎Not found‎‏‎‎‏‎"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‎‎‏‏‎‎‎‎‏‎‏‏‏‏‎‎‏‏‎‎‎‏‎‎‏‎‏‎‎‏‎‏‎‎‎‎‎‏‎‏‎‎‏‎‎‎‎‏‎‎‏‏‎‎‏‎‏‎‎Control is unavailable‎‏‎‎‏‎"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‏‎‎‎‎‏‏‏‏‎‎‏‏‎‏‏‎‏‏‎‏‏‎‏‎‏‎‎‏‎‎‎‎‏‏‏‎‎‏‏‎‎‏‏‎‏‎‏‎‎‎‎‏‎‎‏‎‎1 device selected‎‏‎‎‏‎"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‏‎‎‏‎‏‏‎‏‏‏‎‏‏‎‏‎‏‏‏‏‎‏‏‏‎‏‎‏‎‎‏‏‏‎‎‏‏‏‎‎‎‎‏‏‎‏‏‎‏‎‎‎‏‏‏‎‎‎‏‎‎‏‏‎<xliff:g id="COUNT">%1$d</xliff:g>‎‏‎‎‏‏‏‎ devices selected‎‏‎‎‏‎"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‎‎‏‏‎‎‏‏‎‏‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‎‏‎‏‏‎‏‏‏‎‎‎‎‎‎‏‎‏‏‎‏‎‎‎‏‎‎‏‎‎‎‏‎(disconnected)‎‏‎‎‏‎"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‎‎‏‏‎‎‎‎‏‎‎‎‏‎‏‏‎‏‏‏‎‎‏‎‏‏‎‏‎‎‎‏‏‎‏‎‎‏‎‎‎‏‏‎‏‎‏‎‏‎‏‏‎‎‎‎‏‎‎Couldn\'t connect. Try again.‎‏‎‎‏‎"</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‎‏‏‎‎‎‎‎‏‏‏‎‏‎‎‎‎‎‏‎‎‎‏‏‎‏‎‏‎‎‏‏‏‏‎‎‎‏‎‏‏‎‏‎‎‎‎‎‏‎‏‏‏‏‎‏‏‎Can\'t switch. Tap to try again.‎‏‎‎‏‎"</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‏‏‎‎‏‎‏‎‏‏‎‎‏‏‎‎‎‏‎‏‎‎‏‎‎‏‏‏‎‏‏‎‏‎‎‏‏‎‎Pair new device‎‏‎‎‏‎"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‎‎‏‎‎‏‎‎‎‎‎‎‏‏‏‎‎‎‎‎‎‏‎‎‏‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‎‎‎‎‏‏‏‏‎‎‎‎‏‎‎‏‎‎Build number‎‏‎‎‏‎"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‎‎‎‎‏‎‏‏‏‎‎‏‎‎‏‎‏‎‏‎‎‎‎‏‏‏‎‎‏‎‎‎‎‎‎‎‏‏‏‎‎‏‎‏‏‏‏‎‎‎‎‏‎‎‎‏‏‎‎Build number copied to clipboard.‎‏‎‎‏‎"</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‎‎‏‎‏‏‏‏‎‏‏‎‎‎‎‏‎‎‎‎‎‎‎‎‎‎‏‏‎‏‏‏‏‏‎‏‏‎‏‏‏‏‏‏‎‏‏‏‎‏‏‏‏‏‎‏‎‎See all‎‏‎‎‏‎"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‎‏‏‏‏‎‏‎‎‎‏‏‏‏‎‎‎‏‎‎‎‏‏‏‎‏‏‏‏‎‎‏‎‏‎‎‎‏‏‏‏‏‎‎‎‎‏‏‏‏‎‎‏‎‎‏‏‎To switch networks, disconnect ethernet‎‏‎‎‏‎"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‎‎‎‎‏‏‎‎‎‎‏‎‏‎‎‎‏‎‎‏‎‏‎‏‏‏‎‏‎‏‏‎‏‎‏‏‏‎‎‎‏‎‎‎‏‎‏‏‎‏‏‏‎‎‎‏‎‎To improve device experience, apps and services can still scan for Wi‑Fi networks at any time, even when Wi‑Fi is off. You can change this in Wi‑Fi scanning settings. ‎‏‎‎‏‏‎"<annotation id="link">"‎‏‎‎‏‏‏‎Change‎‏‎‎‏‏‎"</annotation>"‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‎‏‏‏‎‏‏‎‏‏‎‏‏‎‎‏‏‎‏‏‎‏‏‏‎‎‎‎‏‎‎‏‎‏‏‏‏‏‏‏‏‎‎‎‏‏‎‎‏‎‏‏‎‎‎‏‏‎Turn off airplane mode‎‏‎‎‏‎"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‎‎‏‎‎‎‎‏‎‏‎‏‎‏‏‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‏‏‎‎‎‎‏‏‏‏‏‎‏‎‏‎‏‏‎‏‏‏‏‎‏‏‎‎Select user‎‏‎‎‏‎"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‏‎‎‎‏‏‎‏‎‏‏‏‎‏‎‎‎‎‎‎‎‏‎‏‏‏‏‏‎‏‎‎‏‏‏‏‏‎‏‏‎‎‎‏‎‏‎‏‏‏‏‏‎‏‏‎‏‎Apps running in the background‎‏‎‎‏‎"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‏‏‏‎‎‎‎‏‎‎‎‎‎‏‎‎‏‎‎‎‏‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‎‏‎‏‎‏‏‎‏‎‎‎‎‏‎‎‎‎‏‎‎‎Stop‎‏‎‎‏‎"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rXC/tiles_states_strings.xml b/packages/SystemUI/res/values-en-rXC/tiles_states_strings.xml
index 78f4137..0012b57 100644
--- a/packages/SystemUI/res/values-en-rXC/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‎‎‎‎‎‎‏‏‏‎‎‎‎‎‎‏‏‎‎‏‎‎‏‏‏‏‏‎‎‏‏‎‏‎‏‏‎‏‎‏‎‏‎‎‏‏‎‎‏‏‏‎‏‎‎‏‎‎Off‎‏‎‎‏‎"</item>
     <item msgid="460891964396502657">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‎‎‏‏‎‎‏‎‏‎‏‏‎‏‎‏‎‏‏‎‎‏‏‎‎‏‎‏‏‏‎‎‏‏‎‏‎‏‏‏‏‎‏‏‏‏‏‏‎‏‎‎‎‎‎‎‏‎On‎‏‎‎‏‎"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‎‎‏‏‎‎‎‏‏‎‎‏‏‎‎‏‏‏‎‎‎‏‎‏‏‏‎‎‏‎‎‎‏‎‏‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‎‏‏‎‎Unavailable‎‏‎‎‏‎"</item>
+    <item msgid="5581384648880018330">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‎‏‎‏‏‏‎‏‎‏‎‎‎‎‏‏‏‏‏‏‎‎‎‏‎‎‎‏‎‎‎‏‏‏‎‏‎‎‏‏‏‏‏‏‎‏‎‎‏‏‏‎‎‏‏‎‏‎‎Off‎‏‎‎‏‎"</item>
+    <item msgid="8000850843692192257">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‏‎‎‎‎‏‎‎‎‏‎‏‏‏‎‏‏‎‏‏‏‎‎‏‏‏‎‏‏‎‏‏‏‎‎‏‎‏‎‎‎‎‏‎‏‎‎‏‎‎‎‎‎‎‎‎‏‎On‎‏‎‎‏‎"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index fd18230..9065e7f 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"No hay dispositivos disponibles"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Red Wi-Fi no conectada"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Brillo"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Invertir colores"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inversión de color"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"Más configuraciones"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Configuración del usuario"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"Listo"</string>
@@ -743,11 +743,11 @@
     <string name="accessibility_control_move_down" msgid="5390922476900974512">"Mover hacia abajo"</string>
     <string name="accessibility_control_move_left" msgid="8156206978511401995">"Mover hacia la izquierda"</string>
     <string name="accessibility_control_move_right" msgid="8926821093629582888">"Mover hacia la derecha"</string>
-    <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Botón de ampliación"</string>
+    <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Interruptor de ampliación"</string>
     <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Ampliar pantalla completa"</string>
     <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Ampliar parte de la pantalla"</string>
-    <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Botón"</string>
-    <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"El botón de accesibilidad ha reemplazado el gesto de accesibilidad\n\n"<annotation id="link">"Ver configuración"</annotation></string>
+    <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Interruptor"</string>
+    <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Presiona para abrir las funciones de accesibilidad. Personaliza o cambia botón en Config.\n\n"<annotation id="link">"Ver config"</annotation></string>
     <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Mueve el botón hacia el borde para ocultarlo temporalmente"</string>
     <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Mover arriba a la izquierda"</string>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Mover arriba a la derecha"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Configuración"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"Se está reproduciendo <xliff:g id="SONG_NAME">%1$s</xliff:g>, de <xliff:g id="ARTIST_NAME">%2$s</xliff:g>, en <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> de <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"Reproducir"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"Pausar"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"Pista anterior"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"Pista siguiente"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Reproducir"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Abre <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Reproduce <xliff:g id="SONG_NAME">%1$s</xliff:g>, de <xliff:g id="ARTIST_NAME">%2$s</xliff:g>, en <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Reproducir <xliff:g id="SONG_NAME">%1$s</xliff:g> en <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"Deshacer"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Acércate para reproducir en <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"Reproduciendo en <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Inactivo. Verifica la app"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"No se encontró"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"El control no está disponible"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"Se seleccionó 1 dispositivo"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"Se seleccionaron <xliff:g id="COUNT">%1$d</xliff:g> dispositivos"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(desconectado)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"No se pudo establecer la conexión. Vuelve a intentarlo."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"No se pudo conectar. Presiona para volver a intentarlo."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Vincular dispositivo nuevo"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Número de compilación"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Se copió el número de compilación en el portapapeles."</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"Ver todo"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Para cambiar de red, desconéctate de Ethernet"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Para mejorar la experiencia con el dispositivo, las apps y los servicios pueden seguir buscando redes Wi-Fi en cualquier momento, incluso cuando la conexión Wi-Fi esté desactivada. Puedes cambiar este parámetro en la configuración de búsqueda de Wi-Fi. "<annotation id="link">"Cambiar"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Desactivar el modo de avión"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Seleccionar usuario"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Apps en ejecución en segundo plano"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Detener"</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 d70aa53..afb0e72 100644
--- a/packages/SystemUI/res/values-es-rUS/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"No"</item>
     <item msgid="460891964396502657">"Sí"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"No disponible"</item>
+    <item msgid="5581384648880018330">"Desactivado"</item>
+    <item msgid="8000850843692192257">"Activado"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index a2eb152..cf3b2f7 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -20,7 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"UI del sistema"</string>
-    <string name="battery_low_title" msgid="6891106956328275225">"Es posible que te quedes sin batería pronto"</string>
+    <string name="battery_low_title" msgid="6891106956328275225">"Puede que te quedes sin batería pronto"</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"Queda un <xliff:g id="PERCENTAGE">%s</xliff:g> de batería"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"No se puede cargar por USB"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"Utiliza el cargador original incluido con el dispositivo"</string>
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"No hay dispositivos disponibles"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi‑Fi no conectado"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Brillo"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Invertir colores"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Invertir colores"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"Más ajustes"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Ajustes de usuario"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"Hecho"</string>
@@ -747,7 +747,7 @@
     <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Ampliar pantalla completa"</string>
     <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Ampliar parte de la pantalla"</string>
     <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Cambiar"</string>
-    <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"El botón Accesibilidad ha reemplazado el gesto de accesibilidad\n\nVer ajustes"<annotation id="link"></annotation></string>
+    <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Toca para abrir funciones de accesibilidad. Personaliza o sustituye este botón en Ajustes.\n\n"<annotation id="link">"Ver ajustes"</annotation></string>
     <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Mueve el botón hacia el borde para ocultarlo temporalmente"</string>
     <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Mover arriba a la izquierda"</string>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Mover arriba a la derecha"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Ajustes"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"Se está reproduciendo <xliff:g id="SONG_NAME">%1$s</xliff:g> de <xliff:g id="ARTIST_NAME">%2$s</xliff:g> en <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> de <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"Reproducir"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"Pausar"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"Pista anterior"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"Siguiente pista"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Reproducir"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Abrir <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Poner <xliff:g id="SONG_NAME">%1$s</xliff:g> de <xliff:g id="ARTIST_NAME">%2$s</xliff:g> en <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Poner <xliff:g id="SONG_NAME">%1$s</xliff:g> en <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"Deshacer"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Acércate a <xliff:g id="DEVICENAME">%1$s</xliff:g> para que se reproduzca en ese dispositivo"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"Reproduciendo en <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Inactivo, comprobar aplicación"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"No se ha encontrado"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Control no disponible"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 dispositivo seleccionado"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> dispositivos seleccionados"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(desconectado)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"No se ha podido conectar. Inténtalo de nuevo."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"No se puede cambiar. Toca para volver a intentarlo."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Emparejar nuevo dispositivo"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Número de compilación"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Número de compilación copiado en el portapapeles."</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"Ver todo"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Para cambiar de red, desconecta el cable Ethernet"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Para mejorar la experiencia con el dispositivo, las aplicaciones y los servicios podrán buscar redes Wi-Fi en cualquier momento, aunque la conexión Wi-Fi esté desactivada. Puedes cambiarlo en los ajustes de búsqueda de redes Wi-Fi. "<annotation id="link">"Cambiar"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Desactivar modo avión"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Seleccionar usuario"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Aplicaciones ejecutándose en segundo plano"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Detener"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-es/tiles_states_strings.xml b/packages/SystemUI/res/values-es/tiles_states_strings.xml
index 9773954..dd1ed43 100644
--- a/packages/SystemUI/res/values-es/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-es/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"Desactivado"</item>
     <item msgid="460891964396502657">"Activado"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"No disponible"</item>
+    <item msgid="5581384648880018330">"Desactivado"</item>
+    <item msgid="8000850843692192257">"Activado"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index f1acddaf..1494f0f 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Ühtegi seadet pole saadaval"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"WiFi-ühendus puudub"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Heledus"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Värvide vahetamine"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Värvide ümberpööramine"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"Rohkem seadeid"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Kasutaja seaded"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"Valmis"</string>
@@ -747,7 +747,7 @@
     <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Täisekraani suurendamine"</string>
     <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Ekraanikuva osa suurendamine"</string>
     <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Vaheta"</string>
-    <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Juurdepääsetavuse nupp asendas juurdepääsuliigutuse\n\n"<annotation id="link">"Vaadake seadeid"</annotation></string>
+    <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Puudutage juurdepääsufunktsioonide avamiseks. Kohandage nuppu või asendage see seadetes.\n\n"<annotation id="link">"Kuva seaded"</annotation></string>
     <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Teisaldage nupp serva, et see ajutiselt peita"</string>
     <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Teisalda üles vasakule"</string>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Teisalda üles paremale"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Seaded"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> esitajalt <xliff:g id="ARTIST_NAME">%2$s</xliff:g> esitatakse rakenduses <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g>/<xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"Esita"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"Peata"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"Eelmine lugu"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"Järgmine lugu"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Esitamine"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Rakenduse <xliff:g id="APP_LABEL">%1$s</xliff:g> avamine"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Esita lugu <xliff:g id="SONG_NAME">%1$s</xliff:g> esitajalt <xliff:g id="ARTIST_NAME">%2$s</xliff:g> rakenduses <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Esita lugu <xliff:g id="SONG_NAME">%1$s</xliff:g> rakenduses <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"Võta tagasi"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Minge lähemale, et seadmes <xliff:g id="DEVICENAME">%1$s</xliff:g> esitada"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"Esitatakse seadmes <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Passiivne, vaadake rakendust"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Ei leitud"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Juhtelement pole saadaval"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 seade on valitud"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> seadet on valitud"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(ühendus on katkestatud)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Ühenduse loomine ebaõnnestus. Proovige uuesti."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Ei saa lülitada. Puudutage uuesti proovimiseks."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Uue seadme sidumine"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Järgunumber"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Järgunumber kopeeriti lõikelauale."</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"Kuva kõik"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Võrkude vahetamiseks katkestage Etherneti-ühendus"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Seadme kasutuskogemuse parandamiseks võivad rakendused ja teenused siiski alati otsida WiFi-võrke isegi siis, kui WiFi on väljas. Seda saab muuta WiFi-skannimise seadetes. "<annotation id="link">"Muuda"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Lennureżiimi väljalülitamine"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Kasutaja valimine"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Taustal töötavad rakendused"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Peata"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-et/tiles_states_strings.xml b/packages/SystemUI/res/values-et/tiles_states_strings.xml
index 1f14a1c..26fbe80 100644
--- a/packages/SystemUI/res/values-et/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-et/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"Väljas"</item>
     <item msgid="460891964396502657">"Sees"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"Pole saadaval"</item>
+    <item msgid="5581384648880018330">"Väljas"</item>
+    <item msgid="8000850843692192257">"Sees"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index f220cc7..565bc1b 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Ez dago gailurik erabilgarri"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Ez zaude konektatuta wifi-sarera"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Distira"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Alderantzikatu koloreak"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Kolore-alderantzikatzea"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"Ezarpen gehiago"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Erabiltzaile-ezarpenak"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"Eginda"</string>
@@ -747,7 +747,7 @@
     <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Handitu pantaila osoa"</string>
     <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Handitu pantailaren zati bat"</string>
     <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Botoia"</string>
-    <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Erabilerraztasuna botoiak erabilerraztasun-keinua ordezkatu du\n\n"<annotation id="link">"Ikusi ezarpenak"</annotation></string>
+    <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Erabilerraztasun-eginbideak irekitzeko, sakatu hau. Ezarpenetan pertsonalizatu edo ordez dezakezu botoia.\n\n"<annotation id="link">"Ikusi ezarpenak"</annotation></string>
     <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Eraman botoia ertzera aldi baterako ezkutatzeko"</string>
     <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Eraman goialdera, ezkerretara"</string>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Eraman goialdera, eskuinetara"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Ezarpenak"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> (<xliff:g id="ARTIST_NAME">%2$s</xliff:g>) ari da erreproduzitzen <xliff:g id="APP_LABEL">%3$s</xliff:g> bidez"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g>/<xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"Erreproduzitu"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"Pausatu"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"Aurrekoa"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"Hurrengo pista"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Erreproduzitu"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Ireki <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Erreproduzitu <xliff:g id="SONG_NAME">%1$s</xliff:g> (<xliff:g id="ARTIST_NAME">%2$s</xliff:g>) <xliff:g id="APP_LABEL">%3$s</xliff:g> bidez"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Erreproduzitu <xliff:g id="SONG_NAME">%1$s</xliff:g> <xliff:g id="APP_LABEL">%2$s</xliff:g> bidez"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"Desegin"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Gerturatu <xliff:g id="DEVICENAME">%1$s</xliff:g> gailuan erreproduzitzeko"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"<xliff:g id="DEVICENAME">%1$s</xliff:g> pantailan erreproduzitzen"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Inaktibo; egiaztatu aplikazioa"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Ez da aurkitu"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Ez dago erabilgarri kontrolatzeko aukera"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 gailu hautatu da"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> gailu hautatu dira"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(deskonektatuta)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Ezin izan da konektatu. Saiatu berriro."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Ezin da aldatu. Berriro saiatzeko, sakatu hau."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Parekatu beste gailu batekin"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Konpilazio-zenbakia"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Kopiatu da konpilazio-zenbakia arbelean."</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"Ikusi guztiak"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Sarea aldatzeko, deskonektatu Ethernet-a"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Gailuaren funtzionamendua hobetzeko, aplikazioek eta zerbitzuek wifi-sareak bilatzen jarraituko dute, baita wifi-konexioa desaktibatuta dagoenean ere. Aukera hori aldatzeko, joan wifi-sareen bilaketaren ezarpenetara. "<annotation id="link">"Aldatu"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Desaktibatu hegaldi modua"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Hautatu erabiltzaile bat"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Atzeko planoan exekutatzen ari diren aplikazioak"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Gelditu"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-eu/tiles_states_strings.xml b/packages/SystemUI/res/values-eu/tiles_states_strings.xml
index 88e7069..a2a08db 100644
--- a/packages/SystemUI/res/values-eu/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-eu/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"Desaktibatuta"</item>
     <item msgid="460891964396502657">"Aktibatuta"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"Ez dago erabilgarri"</item>
+    <item msgid="5581384648880018330">"Desaktibatuta"</item>
+    <item msgid="8000850843692192257">"Aktibatuta"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 08d13fd..674101d6 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"دستگاهی موجود نیست"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"‏Wi-Fi وصل نیست"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"روشنایی"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"برگردان رنگ‌ها"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"وارونگی رنگ"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"تنظیمات بیشتر"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"تنظیمات کاربر"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"تمام"</string>
@@ -747,7 +747,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="5217151214439341902">"برای باز کردن ویژگی‌های دسترس‌پذیری ضربه بزنید. در تنظیمات این دکمه را سفارشی یا جایگزین کنید\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>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"انتقال به بالا سمت چپ"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"تنظیمات"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> از <xliff:g id="ARTIST_NAME">%2$s</xliff:g> ازطریق <xliff:g id="APP_LABEL">%3$s</xliff:g> پخش می‌شود"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> از <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"پخش"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"توقف موقت"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"آهنگ قبلی"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"آهنگ بعدی"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"پخش"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"باز کردن <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="SONG_NAME">%1$s</xliff:g> از <xliff:g id="ARTIST_NAME">%2$s</xliff:g> را ازطریق <xliff:g id="APP_LABEL">%3$s</xliff:g> پخش کنید"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="SONG_NAME">%1$s</xliff:g> را ازطریق <xliff:g id="APP_LABEL">%2$s</xliff:g> پخش کنید"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"واگرد"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"برای پخش در <xliff:g id="DEVICENAME">%1$s</xliff:g>، به دستگاه نزدیک‌تر شوید"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"درحال پخش در <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"غیرفعال، برنامه را بررسی کنید"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"پیدا نشد"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"کنترل دردسترس نیست"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"۱ دستگاه انتخاب شد"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> دستگاه انتخاب شد"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(اتصال قطع شد)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"متصل نشد. دوباره امتحان کنید."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"عوض نمی‌شود. برای تلاش مجدد ضربه بزنید."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"مرتبط کردن دستگاه جدید"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"شماره ساخت"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"شماره ساخت در بریده‌دان کپی شد."</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"مشاهده همه"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"برای تغییر شبکه، اترنت را قطع کنید"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"‏برای بهبود تجربه استفاده از دستگاه، برنامه‌ها و سرویس‌ها همچنان می‌توانند در هر زمانی شبکه‌های Wi-Fi را اسکن کنند؛ حتی وقتی که Wi-Fi خاموش باشد. می‌توانید این مورد را در تنظیمات اسکن کردن Wi‑Fi تغییر دهید. "<annotation id="link">"تغییر"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"خاموش کردن حالت هواپیما"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"انتخاب کاربر"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"برنامه‌هایی که در پس‌زمینه اجرا می‌شود"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"توقف"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fa/tiles_states_strings.xml b/packages/SystemUI/res/values-fa/tiles_states_strings.xml
index c3d6169..8c40e71 100644
--- a/packages/SystemUI/res/values-fa/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-fa/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"خاموش"</item>
     <item msgid="460891964396502657">"روشن"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"دردسترس نیست"</item>
+    <item msgid="5581384648880018330">"خاموش"</item>
+    <item msgid="8000850843692192257">"روشن"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index f0410e8..432d951 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Laitteita ei ole käytettävissä"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi-Fiä ei ole yhdistetty"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Kirkkaus"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Käänteiset värit"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Käänteiset värit"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"Lisäasetukset"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Käyttäjäasetukset"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"Valmis"</string>
@@ -747,7 +747,7 @@
     <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Koko näytön suurennus"</string>
     <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Suurenna osa näytöstä"</string>
     <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Vaihda"</string>
-    <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Esteettömyyspainike on korvannut esteettömyyseleen\n\n"<annotation id="link">"Katso asetukset"</annotation></string>
+    <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Avaa esteettömyysominaisuudet napauttamalla. Yksilöi tai vaihda painike asetuksista.\n\n"<annotation id="link">"Avaa asetukset"</annotation></string>
     <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Piilota painike tilapäisesti siirtämällä se reunaan"</string>
     <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Siirrä vasempaan yläreunaan"</string>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Siirrä oikeaan yläreunaan"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Asetukset"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g> soittaa nyt tätä: <xliff:g id="SONG_NAME">%1$s</xliff:g> (<xliff:g id="ARTIST_NAME">%2$s</xliff:g>)"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g>/<xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"Toista"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"Keskeytä"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"Edellinen kappale"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"Seuraava kappale"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Toista"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Avaa <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Soita <xliff:g id="SONG_NAME">%1$s</xliff:g> (<xliff:g id="ARTIST_NAME">%2$s</xliff:g>) sovelluksessa <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Soita <xliff:g id="SONG_NAME">%1$s</xliff:g> (<xliff:g id="APP_LABEL">%2$s</xliff:g>)"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"Kumoa"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Siirry lähemmäs, jotta <xliff:g id="DEVICENAME">%1$s</xliff:g> voi toistaa tämän"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"<xliff:g id="DEVICENAME">%1$s</xliff:g> toistaa tämän"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Epäaktiivinen, tarkista sovellus"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Ei löydy"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Ohjain ei ole käytettävissä"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 laite valittu"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> laitetta valittu"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(yhteys katkaistu)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Ei yhteyttä. Yritä uudelleen."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Vaihtaminen ei onnistunut. Yritä uudelleen."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Muodosta uusi laitepari"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Koontiversion numero"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Koontiversion numero kopioitu leikepöydälle"</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"Näytä kaikki"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Irrota Ethernet-johto, jos haluat vaihtaa verkkoa"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Laitteen käyttökokemuksen parantamiseksi sovellukset ja palvelut voivat hakea Wi-Fi-verkkoja myös silloin, kun Wi-Fi on pois päältä. Voit muuttaa asetusta Wi-Fi-haun asetuksissa. "<annotation id="link">"Muuta"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Laita lentokonetila pois päältä"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Valitse käyttäjä"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Sovellukset jotka ovat käynnissä taustalla"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Lopeta"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fi/tiles_states_strings.xml b/packages/SystemUI/res/values-fi/tiles_states_strings.xml
index 7e7468d..cb9e07c 100644
--- a/packages/SystemUI/res/values-fi/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-fi/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"Poissa päältä"</item>
     <item msgid="460891964396502657">"Päällä"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"Ei saatavilla"</item>
+    <item msgid="5581384648880018330">"Poissa päältä"</item>
+    <item msgid="8000850843692192257">"Päällä"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 1825a02..1123c40 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Aucun appareil à proximité"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Non connecté au Wi-Fi"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Luminosité"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Inverser les couleurs"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inversion des couleurs"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"Plus de paramètres"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Paramètres utilisateur"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"Terminé"</string>
@@ -747,7 +747,7 @@
     <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Agrandir la totalité de l\'écran"</string>
     <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Agrandir une partie de l\'écran"</string>
     <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Commutateur"</string>
-    <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Le bouton d\'accessibilité a remplacé le geste d\'accessibilité\n\n"<annotation id="link">"Voir les paramètres"</annotation></string>
+    <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Touchez pour ouvrir fonction. d\'access. Personnalisez ou remplacez bouton dans Param.\n\n"<annotation id="link">"Afficher param."</annotation></string>
     <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Déplacez le bouton vers le bord pour le masquer temporairement"</string>
     <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Déplacer dans coin sup. gauche"</string>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Déplacer dans coin sup. droit"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Paramètres"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> par <xliff:g id="ARTIST_NAME">%2$s</xliff:g> est en cours de lecteur à partir de <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> de <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"Faire jouer"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"Interrompre"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"Chanson précédente"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"Chanson suivante"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Faire jouer"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Ouvrez <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Lecture de <xliff:g id="SONG_NAME">%1$s</xliff:g> par <xliff:g id="ARTIST_NAME">%2$s</xliff:g> à partir de <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Lecture de <xliff:g id="SONG_NAME">%1$s</xliff:g> à partir de <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"Annuler"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Rapprochez-vous pour faire jouer le contenu sur <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"Lecture sur <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Délai expiré, vérifiez l\'appli"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Introuvable"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"La commande n\'est pas accessible"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"Un appareil sélectionné"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> appareil sélectionné"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(déconnecté)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Impossible de se connecter. Réessayez."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Changement impossible. Touchez pour réessayer."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Associer un autre appareil"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Numéro de version"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Le numéro de version a été copié dans le presse-papiers."</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"Tout afficher"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Pour changer de réseau, débranchez le câble Ethernet"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Pour améliorer l\'expérience de l\'appareil, les applications et les services peuvent quand même rechercher des réseaux Wi-Fi en tout temps, même lorsque le Wi-Fi est désactivé. Vous pouvez modifier vos préférences dans les paramètres de recherche de réseaux Wi-Fi. "<annotation id="link">"Modifier"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Désactiver le mode Avion"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Sélect. utilisateur"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Applications exécutées en arrière-plan"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Arrêter"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/tiles_states_strings.xml b/packages/SystemUI/res/values-fr-rCA/tiles_states_strings.xml
index bce1dde..eb38d94 100644
--- a/packages/SystemUI/res/values-fr-rCA/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"Désactivé"</item>
     <item msgid="460891964396502657">"Activé"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"Non disponible"</item>
+    <item msgid="5581384648880018330">"Désactivé"</item>
+    <item msgid="8000850843692192257">"Activé"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 8b6a490..74ad1bd 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Aucun appareil disponible."</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi-Fi non connecté"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Luminosité"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Inverser les couleurs"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inversion des couleurs"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"Plus de paramètres"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Paramètres utilisateur"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"OK"</string>
@@ -747,7 +747,7 @@
     <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Agrandir tout l\'écran"</string>
     <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Agrandir une partie de l\'écran"</string>
     <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Changer"</string>
-    <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Le bouton Accessibilité a remplacé le geste d\'accessibilité\n\n"<annotation id="link">"Afficher les paramètres"</annotation></string>
+    <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Appuyez pour ouvrir fonctionnalités d\'accessibilité. Personnalisez ou remplacez bouton dans paramètres.\n\n"<annotation id="link">"Voir paramètres"</annotation></string>
     <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Déplacer le bouton vers le bord pour le masquer temporairement"</string>
     <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Déplacer en haut à gauche"</string>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Déplacer en haut à droite"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Paramètres"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> par <xliff:g id="ARTIST_NAME">%2$s</xliff:g> est en cours de lecture depuis <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> sur <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"Lecture"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"Pause"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"Titre précédent"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"Titre suivant"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Lire"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Ouvre <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Mets <xliff:g id="SONG_NAME">%1$s</xliff:g> par <xliff:g id="ARTIST_NAME">%2$s</xliff:g> depuis <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Mets <xliff:g id="SONG_NAME">%1$s</xliff:g> depuis <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"Annuler"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Rapprochez-vous pour lire sur <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"Lecture sur <xliff:g id="DEVICENAME">%1$s</xliff:g>…"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Délai expiré, vérifier l\'appli"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Introuvable"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Commande indisponible"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 appareil sélectionné"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> appareils sélectionnés"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(déconnecté)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Impossible de se connecter. Réessayez."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Impossible de changer. Appuyez pour réessayer."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Associer un nouvel appareil"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Numéro de build"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Numéro de build copié dans le presse-papiers."</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"Tout afficher"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Pour changer de réseau, déconnectez l\'Ethernet"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Pour améliorer l\'expérience sur l\'appareil, les applis et les services peuvent continuer de rechercher les réseaux Wi-Fi, même si le Wi-Fi est désactivé. Vous pouvez modifier cela dans les paramètres de recherche Wi-Fi. "<annotation id="link">"Modifier"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Désactiver le mode Avion"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Choisir utilisateur"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Applis exécutées en arrière-plan"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Arrêter"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fr/tiles_states_strings.xml b/packages/SystemUI/res/values-fr/tiles_states_strings.xml
index a2e2f73..3aefb1d 100644
--- a/packages/SystemUI/res/values-fr/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-fr/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"Désactivé"</item>
     <item msgid="460891964396502657">"Activé"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"Indisponible"</item>
+    <item msgid="5581384648880018330">"Désactivé"</item>
+    <item msgid="8000850843692192257">"Activé"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 6c21265..121d434 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Non hai dispositivos dispoñibles"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"A wifi non está conectada"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Brillo"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Inverter cores"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inversión da cor"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"Máis opcións"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Configuración de usuario"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"Feito"</string>
@@ -747,7 +747,7 @@
     <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Ampliar pantalla completa"</string>
     <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Amplía parte da pantalla"</string>
     <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Cambiar"</string>
-    <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"O botón de accesibilidade substituíu o xesto de accesibilidade\n\n"<annotation id="link">"Ver configuración"</annotation></string>
+    <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Toca para abrir as funcións de accesibilidade. Cambia este botón en Configuración.\n\n"<annotation id="link">"Ver configuración"</annotation></string>
     <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Para ocultar temporalmente o botón, móveo ata o bordo"</string>
     <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Mover á parte super. esquerda"</string>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Mover á parte superior dereita"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Configuración"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"Estase reproducindo <xliff:g id="SONG_NAME">%1$s</xliff:g>, de <xliff:g id="ARTIST_NAME">%2$s</xliff:g>, en <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> de <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"Reproducir"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"Pór en pausa"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"Pista anterior"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"Pista seguinte"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Reproducir"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Abre <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Reproduce <xliff:g id="SONG_NAME">%1$s</xliff:g>, de <xliff:g id="ARTIST_NAME">%2$s</xliff:g>, en <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Reproduce <xliff:g id="SONG_NAME">%1$s</xliff:g> en <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"Desfacer"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Achega o dispositivo para reproducir a música en: <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"Estase reproducindo o contido en: <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Inactivo. Comproba a app"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Non se atopou"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"O control non está dispoñible"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"Seleccionouse 1 dispositivo"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"Seleccionáronse <xliff:g id="COUNT">%1$d</xliff:g> dispositivos"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(desconectado)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Non se puido establecer a conexión. Téntao de novo."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Non se puido realizar o cambio. Toca para tentalo de novo."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Vincular dispositivo novo"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Número de compilación"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Copiouse o número de compilación no portapapeis."</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"Ver todo"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Para cambiar de rede, desconecta a Ethernet"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Para mellorar a experiencia que ofrece o dispositivo, as aplicacións e os servizos poden seguir buscando redes wifi en calquera momento, aínda que esta conexión estea desactivada. Podes cambiar esta opción na configuración da función Busca de redes wifi. "<annotation id="link">"Cambiar"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Desactivar modo avión"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Seleccionar usuario"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Aplicacións que se están executando en segundo plano"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Deter"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-gl/tiles_states_strings.xml b/packages/SystemUI/res/values-gl/tiles_states_strings.xml
index 7819fbb..90dcf7d 100644
--- a/packages/SystemUI/res/values-gl/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-gl/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"Desactivado"</item>
     <item msgid="460891964396502657">"Activado"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"Non dispoñible"</item>
+    <item msgid="5581384648880018330">"Desactivado"</item>
+    <item msgid="8000850843692192257">"Activado"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index f1bd364..c397848 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"કોઈ ઉપકરણો ઉપલબ્ધ નથી"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"વાઇ-ફાઇ કનેક્ટ નથી"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"તેજ"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"રંગોને ઉલટાવો"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"વિપરીત રંગમાં બદલવું"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"વધુ સેટિંગ"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"વપરાશકર્તા સેટિંગ"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"થઈ ગયું"</string>
@@ -334,7 +334,7 @@
     <string name="user_new_user_name" msgid="2019166282704195789">"નવો વપરાશકર્તા"</string>
     <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"અતિથિ દૂર કરીએ?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"આ સત્રમાંની તમામ ઍપ અને ડેટા કાઢી નાખવામાં આવશે."</string>
-    <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"દૂર કરો"</string>
+    <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"કાઢી નાખો"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"ફરી સ્વાગત છે, અતિથિ!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"શું તમે તમારું સત્ર ચાલુ રાખવા માંગો છો?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"શરૂ કરો"</string>
@@ -747,7 +747,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="5217151214439341902">"ઍક્સેસિબિલિટી સુવિધાઓ ખોલવા માટે ટૅપ કરો. સેટિંગમાં આ બટનને કસ્ટમાઇઝ કરો અથવા બદલો.\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>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"ઉપર જમણે ખસેડો"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"સેટિંગ"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g> પર <xliff:g id="ARTIST_NAME">%2$s</xliff:g>નું <xliff:g id="SONG_NAME">%1$s</xliff:g> ગીત ચાલી રહ્યું છે"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="TOTAL_TIME">%2$s</xliff:g>માંથી <xliff:g id="ELAPSED_TIME">%1$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"ચલાવો"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"થોભાવો"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"પહેલાનો ટ્રૅક"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"આગલો ટ્રૅક"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"ચલાવો"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> ખોલો"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="APP_LABEL">%3$s</xliff:g> પર <xliff:g id="ARTIST_NAME">%2$s</xliff:g>નું <xliff:g id="SONG_NAME">%1$s</xliff:g> ગીત ચલાવો"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="APP_LABEL">%2$s</xliff:g> પર <xliff:g id="SONG_NAME">%1$s</xliff:g> ગીત ચલાવો"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"છેલ્લો ફેરફાર રદ કરો"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"<xliff:g id="DEVICENAME">%1$s</xliff:g> પર ચલાવવા માટે વધુ નજીક ખસેડો"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"<xliff:g id="DEVICENAME">%1$s</xliff:g> પર ચલાવવામાં આવી રહ્યું છે"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"નિષ્ક્રિય, ઍપને ચેક કરો"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"મળ્યું નથી"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"નિયંત્રણ ઉપલબ્ધ નથી"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 ડિવાઇસ પસંદ કર્યું"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> ડિવાઇસ પસંદ કર્યા"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(ડિસ્કનેક્ટ કરેલું)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"કનેક્ટ કરી શકાયું નહીં. ફરી પ્રયાસ કરો."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"સ્વિચ કરી શકતા નથી. ફરી પ્રયાસ કરવા માટે ટૅપ કરો."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"નવા ડિવાઇસ સાથે જોડાણ કરો"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"બિલ્ડ નંબર"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"બિલ્ડ નંબર ક્લિપબૉર્ડ પર કૉપિ કર્યો."</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"બધા જુઓ"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"બીજા નેટવર્ક પર જવા માટે, ઇથરનેટ ડિસ્કનેક્ટ કરો"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"ડિવાઇસના અનુભવને બહેતર બનાવવા માટે, વાઇ-ફાઇ બંધ હોય ત્યારે પણ ઍપ અને સેવાઓ કોઈપણ સમયે વાઇ-ફાઇ નેટવર્ક સ્કૅન કરી શકે છે. તમે વાઇ-ફાઇ સ્કૅનિંગના સેટિંગમાં જઈને આને બદલી શકો છો. "<annotation id="link">"બદલો"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"એરપ્લેન મોડ બંધ કરો"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"વપરાશકર્તા પસંદ કરો"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"બૅકગ્રાઉન્ડમાં ચાલતી ઍપ"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"રોકો"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-gu/tiles_states_strings.xml b/packages/SystemUI/res/values-gu/tiles_states_strings.xml
index ddf18f6..e50f3cf 100644
--- a/packages/SystemUI/res/values-gu/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-gu/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"બંધ છે"</item>
     <item msgid="460891964396502657">"ચાલુ છે"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"અનુપલબ્ધ"</item>
+    <item msgid="5581384648880018330">"બંધ છે"</item>
+    <item msgid="8000850843692192257">"ચાલુ છે"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 72eb309..098b2a1 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"कोई डिवाइस उपलब्ध नहीं"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"वाई-फ़ाई कनेक्ट नहीं है"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"स्क्रीन की रोशनी"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"रंग उलटें"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"रंग बदलने की सुविधा"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"और सेटिंग"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"उपयोगकर्ता सेटिंग"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"हो गया"</string>
@@ -689,7 +689,7 @@
     <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_storage" msgid="2720725707628094977">"जगह"</string>
+    <string name="notification_channel_storage" msgid="2720725707628094977">"स्टोरेज"</string>
     <string name="notification_channel_hints" msgid="7703783206000346876">"संकेत"</string>
     <string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string>
     <string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> चल रहा है"</string>
@@ -747,7 +747,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="5217151214439341902">"सुलभता सुविधाएं खोलने के लिए टैप करें. सेटिंग में, इस बटन को बदलें या अपने हिसाब से सेट करें.\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>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"सबसे ऊपर दाईं ओर ले जाएं"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"सेटिंग"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g> पर, <xliff:g id="ARTIST_NAME">%2$s</xliff:g> का <xliff:g id="SONG_NAME">%1$s</xliff:g> चल रहा है"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="TOTAL_TIME">%2$s</xliff:g> में से <xliff:g id="ELAPSED_TIME">%1$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"चलाएं"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"रोकें"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"पिछला ट्रैक"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"अगला ट्रैक"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"चलाएं"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> खोलें"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="APP_LABEL">%3$s</xliff:g> पर, <xliff:g id="ARTIST_NAME">%2$s</xliff:g> का <xliff:g id="SONG_NAME">%1$s</xliff:g> चलाएं"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="APP_LABEL">%2$s</xliff:g> पर, <xliff:g id="SONG_NAME">%1$s</xliff:g> चलाएं"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"पहले जैसा करें"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"<xliff:g id="DEVICENAME">%1$s</xliff:g> पर गाने चलाने के लिए उसके पास जाएं"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"<xliff:g id="DEVICENAME">%1$s</xliff:g> पर चल रहा है"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"काम नहीं कर रहा, ऐप जांचें"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"कंट्रोल नहीं है"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"कंट्रोल मौजूद नहीं है"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"एक डिवाइस चुना गया"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> डिवाइस चुने गए"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(डिसकनेक्ट हो गया)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"कनेक्ट नहीं किया जा सका. फिर से कोशिश करें."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"स्विच नहीं किया जा सकता. फिर से कोशिश करने के लिए टैप करें."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"नया डिवाइस जोड़ें"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"बिल्ड नंबर"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"बिल्ड नंबर को क्लिपबोर्ड पर कॉपी किया गया."</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"सभी देखें"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"नेटवर्क बदलने के लिए, पहले ईथरनेट को डिसकनेक्ट करें"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"डिवाइस इस्तेमाल करने के अनुभव काे बेहतर बनाने के लिए, ऐप्लिकेशन और सेवाओं की मदद से, किसी भी समय वाई-फ़ाई नेटवर्क स्कैन किए जा सकते हैं. ऐसा वाई-फ़ाई बंद होने पर भी किया जा सकता है. वाई-फ़ाई स्कैनिंग की सेटिंग में जाकर, इसे बदला जा सकता है. "<annotation id="link">"बदलें"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"हवाई जहाज़ मोड बंद करें"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"उपयोगकर्ता चुनें"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"बैकग्राउंड में चल रहे ऐप्लिकेशन"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"बंद करें"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hi/tiles_states_strings.xml b/packages/SystemUI/res/values-hi/tiles_states_strings.xml
index 08db65b..7698912 100644
--- a/packages/SystemUI/res/values-hi/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-hi/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"बंद है"</item>
     <item msgid="460891964396502657">"चालू है"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"उपलब्ध नहीं है"</item>
+    <item msgid="5581384648880018330">"बंद है"</item>
+    <item msgid="8000850843692192257">"चालू है"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index e549d725..45fa359 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -251,7 +251,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Nema dostupnih uređaja"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi-Fi mreža nije povezana"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Svjetlina"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Zamjena boja"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inverzija boja"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"Više  postavki"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Korisničke postavke"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"Gotovo"</string>
@@ -752,7 +752,7 @@
     <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Povećajte cijeli zaslon"</string>
     <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Povećaj dio zaslona"</string>
     <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Prebacivanje"</string>
-    <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Gumb za Pristupačnost zamijenio je pokret pristupačnosti\n\n"<annotation id="link">"Prikaz postavki"</annotation></string>
+    <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Dodirnite za otvaranje značajki pristupačnosti. Prilagodite ili zamijenite taj gumb u postavkama.\n\n"<annotation id="link">"Pregledajte postavke"</annotation></string>
     <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Pomaknite gumb do ruba da biste ga privremeno sakrili"</string>
     <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Premjesti u gornji lijevi kut"</string>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Premjesti u gornji desni kut"</string>
@@ -804,10 +804,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Postavke"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g>, <xliff:g id="ARTIST_NAME">%2$s</xliff:g> reproducira se putem aplikacije <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> od <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"Reproduciraj"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"Pauziraj"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"Prethodni zapis"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"Sljedeći zapis"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Reprodukcija"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Otvori <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Pustite <xliff:g id="SONG_NAME">%1$s</xliff:g>, <xliff:g id="ARTIST_NAME">%2$s</xliff:g> putem aplikacije <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Pustite <xliff:g id="SONG_NAME">%1$s</xliff:g> putem aplikacije <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"Poništi"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Približite se radi reprodukcije na uređaju <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"Reproducira se na uređaju <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Neaktivno, provjerite aplik."</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Nije pronađeno"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrola nije dostupna"</string>
@@ -822,7 +829,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"Odabran je jedan uređaj"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"Odabrano uređaja: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(nije povezano)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Povezivanje nije bilo moguće. Pokušajte ponovo."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Nije prebačeno. Dodirnite da biste pokušali ponovo."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Uparite novi uređaj"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Broj međuverzije"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Broj međuverzije kopiran je u međuspremnik."</string>
@@ -887,8 +894,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"Prikaži sve"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Da biste se prebacili na drugu mrežu, odspojite Ethernet"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Da bi se poboljšao doživljaj uređaja, aplikacije i usluge i dalje mogu tražiti Wi-Fi mreže u bilo kojem trenutku, čak i kada je Wi-Fi isključen. To možete promijeniti u postavkama traženja Wi-Fija. "<annotation id="link">"Promijeni"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Isključi način rada u zrakoplovu"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Odabir korisnika"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Aplikacije koje se izvode u pozadini"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Zaustavi"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hr/tiles_states_strings.xml b/packages/SystemUI/res/values-hr/tiles_states_strings.xml
index 5d9edf5..ae9ffb3 100644
--- a/packages/SystemUI/res/values-hr/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-hr/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"Isključeno"</item>
     <item msgid="460891964396502657">"Uključeno"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"Nije dostupno"</item>
+    <item msgid="5581384648880018330">"Isključeno"</item>
+    <item msgid="8000850843692192257">"Uključeno"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 5bb6dd0..5539787 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Nem áll rendelkezésre eszköz"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Nem kapcsolódik Wi‑Fi-hálózathoz"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Fényerő"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Színek invertálása"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Színek invertálása"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"További beállítások"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Felhasználói beállítások"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"Kész"</string>
@@ -747,7 +747,7 @@
     <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"A teljes képernyő felnagyítása"</string>
     <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Képernyő bizonyos részének nagyítása"</string>
     <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Váltás"</string>
-    <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"A kisegítő kézmozdulat helyébe a Kisegítő lehetőségek gomb lépett\n\n"<annotation id="link">"Beállítások megtekintése"</annotation></string>
+    <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Koppintson a kisegítő lehetőségek megnyitásához. A gombot a Beállításokban módosíthatja.\n\n"<annotation id="link">"Beállítások"</annotation></string>
     <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"A gombot a szélre áthelyezve ideiglenesen elrejtheti"</string>
     <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Áthelyezés fel és balra"</string>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Áthelyezés fel és jobbra"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Beállítások"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> <xliff:g id="SONG_NAME">%1$s</xliff:g> című száma hallható itt: <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="TOTAL_TIME">%2$s</xliff:g>/<xliff:g id="ELAPSED_TIME">%1$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"Lejátszás"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"Szünet"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"Előző szám"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"Következő szám"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Játék"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> megnyitása"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> <xliff:g id="SONG_NAME">%1$s</xliff:g> című számának lejátszása innen: <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="SONG_NAME">%1$s</xliff:g> lejátszása innen: <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"Visszavonás"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Menjen közelebb a következőn való lejátszáshoz: <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"Lejátszás folyamatban a(z) <xliff:g id="DEVICENAME">%1$s</xliff:g> eszközön"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Inaktív, ellenőrizze az appot"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Nem található"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Nem hozzáférhető vezérlő"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 eszköz kiválasztva"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> eszköz kiválasztva"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(leválasztva)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Sikertelen csatlakozás. Próbálja újra."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"A váltás nem sikerült. Próbálja újra."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Új eszköz párosítása"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Buildszám"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Buildszám a vágólapra másolva."</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"Megtekintés"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Hálózatváltáshoz válassza le az ethernetet"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Az eszközhasználati élmény javítása érdekében az alkalmazások és a szolgáltatások továbbra is bármikor kereshetnek Wi-Fi-hálózatokat, még akkor is, ha a Wi-Fi ki van kapcsolva. A funkciót a „Wi-Fi scanning settings” (Wi-Fi-keresési beállítások) részben módosíthatja. "<annotation id="link">"Módosítás"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Repülős üzemmód kikapcsolása"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Felhasználóválasztás"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Több alkalmazás is fut a háttérben"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Leállítás"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hu/tiles_states_strings.xml b/packages/SystemUI/res/values-hu/tiles_states_strings.xml
index dbfdf99..140f2db 100644
--- a/packages/SystemUI/res/values-hu/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-hu/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"Ki"</item>
     <item msgid="460891964396502657">"Be"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"Nem áll rendelkezésre"</item>
+    <item msgid="5581384648880018330">"Ki"</item>
+    <item msgid="8000850843692192257">"Be"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 4b02f8b..7323cef 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Հասանելի սարքեր չկան"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi-Fi-ը միացված չէ"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Պայծառություն"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Շրջել գույները"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Գունաշրջում"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"Հավելյալ կարգավորումներ"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Օգտատիրոջ կարգավորումներ"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"Պատրաստ է"</string>
@@ -747,7 +747,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="5217151214439341902">"Հատուկ գործառույթները բացելու համար հպեք։ Անհատականացրեք այս կոճակը կարգավորումներում։\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>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Տեղափոխել վերև՝ աջ"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Կարգավորումներ"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"Այժմ նվագարկվում է <xliff:g id="SONG_NAME">%1$s</xliff:g> երգը <xliff:g id="ARTIST_NAME">%2$s</xliff:g>-ի կատարմամբ <xliff:g id="APP_LABEL">%3$s</xliff:g> հավելվածից"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g>՝ <xliff:g id="TOTAL_TIME">%2$s</xliff:g>-ից"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"Նվագարկել"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"Դադարեցնել"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"Նախորդ կատարումը"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"Հաջորդ կատարումը"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Նվագարկել"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Բացեք <xliff:g id="APP_LABEL">%1$s</xliff:g> հավելվածը"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Նվագարկել <xliff:g id="SONG_NAME">%1$s</xliff:g> երգը <xliff:g id="ARTIST_NAME">%2$s</xliff:g>-ի կատարմամբ <xliff:g id="APP_LABEL">%3$s</xliff:g> հավելվածից"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Նվագարկել <xliff:g id="SONG_NAME">%1$s</xliff:g> երգը <xliff:g id="APP_LABEL">%2$s</xliff:g> հավելվածից"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"Հետարկել"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Ավելի մոտ եկեք՝ <xliff:g id="DEVICENAME">%1$s</xliff:g> սարքում նվագարկելու համար"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"Նվագարկվում է <xliff:g id="DEVICENAME">%1$s</xliff:g> սարքում"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Ակտիվ չէ, ստուգեք հավելվածը"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Չի գտնվել"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Կառավարման տարրը հասանելի չէ"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"Ընտրված է 1 սարք"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"Ընտրված է <xliff:g id="COUNT">%1$d</xliff:g> սարք"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(անջատված է)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Չհաջողվեց միանալ։ Նորից փորձեք։"</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Սխալ առաջացավ։ Հպեք՝ կրկնելու համար։"</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Նոր սարքի զուգակցում"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Կառուցման համարը"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Կառուցման համարը պատճենվեց սեղմատախտակին։"</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"Տեսնել բոլորը"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Մի ցանցից մյուսին անցնելու համար անջատեք Ethernet-ը"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Սարքի աշխատանքը բարելավելու համար հավելվածներն ու ծառայությունները կորոնեն Wi‑Fi ցանցեր, նույնիսկ երբ Wi‑Fi-ն անջատված է։ Այս պարամետրը կարող եք փոխել Wi‑Fi ցանցերի որոնման կարգավորումներում։ "<annotation id="link">"Փոխել"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Անջատել ավիառեժիմը"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Ընտրեք օգտատեր"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Ֆոնային ռեժիմում աշխատող հավելվածներ"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Դադարեցնել"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hy/tiles_states_strings.xml b/packages/SystemUI/res/values-hy/tiles_states_strings.xml
index 323d292..df69ce7 100644
--- a/packages/SystemUI/res/values-hy/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-hy/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"Անջատված է"</item>
     <item msgid="460891964396502657">"Միացված է"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"Հասանելի չէ"</item>
+    <item msgid="5581384648880018330">"Անջատված է"</item>
+    <item msgid="8000850843692192257">"Միացված է"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 546f694..f659465 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Perangkat tak tersedia"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi‑Fi tidak terhubung"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Kecerahan"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Inversi warna"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inversi warna"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"Setelan lainnya"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Setelan pengguna"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"Selesai"</string>
@@ -747,7 +747,7 @@
     <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Memperbesar tampilan layar penuh"</string>
     <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Perbesar sebagian layar"</string>
     <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Alihkan"</string>
-    <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Tombol aksesibilitas menggantikan gestur aksesibilitas\n\n"<annotation id="link">"Tampilkan setelan"</annotation></string>
+    <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Ketuk untuk membuka fitur aksesibilitas. Sesuaikan atau ganti tombol ini di Setelan.\n\n"<annotation id="link">"Lihat setelan"</annotation></string>
     <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Pindahkan tombol ke tepi agar tersembunyi untuk sementara"</string>
     <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Pindahkan ke kiri atas"</string>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Pindahkan ke kanan atas"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Setelan"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> oleh <xliff:g id="ARTIST_NAME">%2$s</xliff:g> sedang diputar dari <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> dari <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"Putar"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"Jeda"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"Lagu sebelumnya"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"Lagu berikutnya"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Putar"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Buka <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Putar <xliff:g id="SONG_NAME">%1$s</xliff:g> oleh <xliff:g id="ARTIST_NAME">%2$s</xliff:g> dari <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Putar <xliff:g id="SONG_NAME">%1$s</xliff:g> dari <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"Urungkan"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Dekatkan untuk memutar di <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"Diputar di <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Nonaktif, periksa aplikasi"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Tidak ditemukan"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrol tidak tersedia"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 perangkat dipilih"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> perangkat dipilih"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(terputus)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Tidak dapat terhubung. Coba lagi."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Tidak dapat beralih. Ketuk untuk mencoba lagi."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Sambungkan perangkat baru"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Nomor build"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Nomor versi disalin ke papan klip."</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"Lihat semua"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Untuk beralih jaringan, lepaskan kabel ethernet"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Agar pengalaman perangkat menjadi lebih baik, aplikasi dan layanan tetap dapat memindai jaringan Wi-Fi kapan saja, bahkan saat Wi-Fi nonaktif. Anda dapat mengubahnya di setelan pemindaian Wi-Fi. "<annotation id="link">"Ubah"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Menonaktifkan mode pesawat"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Pilih pengguna"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Aplikasi berjalan di latar belakang"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Berhenti"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-in/tiles_states_strings.xml b/packages/SystemUI/res/values-in/tiles_states_strings.xml
index 29d50b50..811294f 100644
--- a/packages/SystemUI/res/values-in/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-in/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"Nonaktif"</item>
     <item msgid="460891964396502657">"Aktif"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"Tidak tersedia"</item>
+    <item msgid="5581384648880018330">"Nonaktif"</item>
+    <item msgid="8000850843692192257">"Aktif"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 31fe363..48068b1 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Engin tæki til staðar"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi-Fi ekki tengt"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Birtustig"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Umsnúa litum"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Umsnúningur lita"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"Fleiri stillingar"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Notandastillingar"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"Lokið"</string>
@@ -747,7 +747,7 @@
     <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Stækka allan skjáinn"</string>
     <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Stækka hluta skjásins"</string>
     <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Rofi"</string>
-    <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Aðgengishnappur kom í stað aðgengisbendingar\n\n"<annotation id="link">"Skoða stillingar"</annotation></string>
+    <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Ýttu til að opna aðgengiseiginleika. Sérsníddu eða skiptu hnappinum út í stillingum.\n\n"<annotation id="link">"Skoða stillingar"</annotation></string>
     <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Færðu hnappinn að brúninni til að fela hann tímabundið"</string>
     <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Færa efst til vinstri"</string>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Færa efst til hægri"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Stillingar"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> með <xliff:g id="ARTIST_NAME">%2$s</xliff:g> er í spilun á <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> af <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"Spila"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"Gera hlé"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"Fyrra lag"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"Næsta lag"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Spila"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Opna <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Spila <xliff:g id="SONG_NAME">%1$s</xliff:g> með <xliff:g id="ARTIST_NAME">%2$s</xliff:g> í <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Spila <xliff:g id="SONG_NAME">%1$s</xliff:g> í <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"Afturkalla"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Færðu nær til að spila í <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"Spilast í <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Óvirkt, athugaðu forrit"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Fannst ekki"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Stýring er ekki tiltæk"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 tæki valið"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> tæki valin"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(aftengt)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Tenging mistókst. Reyndu aftur."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Ekki er hægt að skipta. Ýttu til að reyna aftur."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Para nýtt tæki"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Útgáfunúmer smíðar"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Útgáfunúmer smíðar afritað á klippiborð."</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"Sjá allt"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Aftengdu ethernet til að skipta um net"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Til að bæta tækjaupplifun geta forrit og þjónustur áfram leitað að WiFi-netum hvenær sem er, jafnvel þótt slökkt sé á WiFi. Hægt er að breyta þessu í stillingum WiFi-leitar. "<annotation id="link">"Breyta"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Slökkva á flugstillingu"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Velja notanda"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Forrit keyra í bakgrunni"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Stöðva"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-is/tiles_states_strings.xml b/packages/SystemUI/res/values-is/tiles_states_strings.xml
index 4d9a097..dd704a7 100644
--- a/packages/SystemUI/res/values-is/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-is/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"Slökkt"</item>
     <item msgid="460891964396502657">"Kveikt"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"Ekki í boði"</item>
+    <item msgid="5581384648880018330">"Slökkt"</item>
+    <item msgid="8000850843692192257">"Kveikt"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 3b54801..cd53a50 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Nessun dispositivo disponibile"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Nessuna connessione Wi-Fi"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Luminosità"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Inverti colori"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inversione dei colori"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"Altre impostazioni"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Impostazioni utente"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"Fine"</string>
@@ -747,7 +747,7 @@
     <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Ingrandisci l\'intero schermo"</string>
     <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Ingrandisci parte dello schermo"</string>
     <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Opzione"</string>
-    <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Il pulsante Accessibilità ha sostituito il gesto di accessibilità\n\n"<annotation id="link">"Visualizza le impostazioni"</annotation></string>
+    <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Tocca per aprire funzioni di accessibilità. Personalizza o sostituisci il pulsante in Impostazioni.\n\n"<annotation id="link">"Vedi impostazioni"</annotation></string>
     <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Sposta il pulsante fino al bordo per nasconderlo temporaneamente"</string>
     <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Sposta in alto a sinistra"</string>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Sposta in alto a destra"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Impostazioni"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> di <xliff:g id="ARTIST_NAME">%2$s</xliff:g> è in riproduzione da <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> di <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"Riproduci"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"Metti in pausa"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"Traccia precedente"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"Traccia successiva"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Riproduci"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Apri <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Riproduci <xliff:g id="SONG_NAME">%1$s</xliff:g> di <xliff:g id="ARTIST_NAME">%2$s</xliff:g> da <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Riproduci <xliff:g id="SONG_NAME">%1$s</xliff:g> da <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"Annulla"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Avvicinati per riprodurre su <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"In riproduzione su <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Inattivo, controlla l\'app"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Controllo non trovato"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Il controllo non è disponibile"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 dispositivo selezionato"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> dispositivi selezionati"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(disconnesso)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Impossibile connettersi. Riprova."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Non puoi cambiare. Tocca per riprovare."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Accoppia nuovo dispositivo"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Numero build"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Numero build copiato negli appunti."</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"Mostra tutte"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Per cambiare rete, scollega il cavo Ethernet"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Per migliorare l\'esperienza con il dispositivo, le app e i servizi possono continuare a cercare reti Wi-Fi in qualsiasi momento, anche quando la connessione Wi-Fi non è attiva. Puoi modificare questa preferenza nelle impostazioni relative alla ricerca di reti Wi-Fi. "<annotation id="link">"Cambia"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Disattiva la modalità aereo"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Seleziona utente"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"App in esecuzione in background"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Interrompi"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-it/tiles_states_strings.xml b/packages/SystemUI/res/values-it/tiles_states_strings.xml
index db0bbb4..1596998 100644
--- a/packages/SystemUI/res/values-it/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-it/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"Off"</item>
     <item msgid="460891964396502657">"On"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"Non disponibile"</item>
+    <item msgid="5581384648880018330">"Off"</item>
+    <item msgid="8000850843692192257">"On"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 066f3c2..f36827c 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -252,7 +252,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"אין מכשירים זמינים"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"‏אין חיבור ל-Wi-Fi"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"בהירות"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"היפוך צבעים"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"היפוך צבעים"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"הגדרות נוספות"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"הגדרות המשתמש"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"בוצע"</string>
@@ -757,7 +757,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="5217151214439341902">"מקישים כדי לפתוח את תכונות הנגישות. אפשר להחליף את הלחצן או להתאים אותו אישית בהגדרות.\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>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"העברה לפינה הימנית העליונה"</string>
@@ -810,10 +810,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"הגדרות"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> של <xliff:g id="ARTIST_NAME">%2$s</xliff:g> מופעל מ-<xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> מתוך <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"הפעלה"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"השהיה"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"הטראק הקודם"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"הטראק הבא"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"הפעלה"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"פתיחה של <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"הפעלת <xliff:g id="SONG_NAME">%1$s</xliff:g> של <xliff:g id="ARTIST_NAME">%2$s</xliff:g> מ-<xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"הפעלת <xliff:g id="SONG_NAME">%1$s</xliff:g> מ-<xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"ביטול"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"צריך להתקרב כדי להפעיל מוזיקה במכשיר <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"ההפעלה הועברה למכשיר <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"לא פעיל, יש לבדוק את האפליקציה"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"לא נמצא"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"הפקד לא זמין"</string>
@@ -828,7 +835,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"נבחר מכשיר אחד"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"נבחרו <xliff:g id="COUNT">%1$d</xliff:g> מכשירים"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(מנותק)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"לא ניתן היה להתחבר. יש לנסות שוב."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"לא ניתן להחליף. צריך להקיש כדי לנסות שוב."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"התאמה של מכשיר חדש"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"‏מספר Build"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"‏מספר ה-Build הועתק ללוח."</string>
@@ -893,8 +900,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"הצגת הכול"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"כדי לעבור בין רשתות, צריך לנתק את האתרנט"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"‏כדי לשפר את חוויית השימוש במכשיר, אפליקציות ושירותים יוכלו לחפש רשתות Wi-Fi בכל שלב, גם כאשר ה-Wi-Fi כבוי. אפשר לשנות זאת בהגדרות של חיפוש נקודות Wi-Fi. "<annotation id="link">"שינוי"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"השבתה של מצב טיסה"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"בחירת משתמש"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"אפליקציות שפועלות ברקע"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"עצירה"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-iw/tiles_states_strings.xml b/packages/SystemUI/res/values-iw/tiles_states_strings.xml
index 61735cf..28548bc 100644
--- a/packages/SystemUI/res/values-iw/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-iw/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"כבוי"</item>
     <item msgid="460891964396502657">"פועל"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"לא זמין"</item>
+    <item msgid="5581384648880018330">"כבוי"</item>
+    <item msgid="8000850843692192257">"פועל"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 4295e96..6fbcbb3 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"利用可能なデバイスがありません"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi-Fi 未接続"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"画面の明るさ"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"色を反転"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"色反転"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"詳細設定"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"ユーザー設定"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"完了"</string>
@@ -747,7 +747,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="5217151214439341902">"タップしてユーザー補助機能を開きます。ボタンのカスタマイズや入れ替えを [設定] で行えます。\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>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"右上に移動"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"設定"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g>(アーティスト名: <xliff:g id="ARTIST_NAME">%2$s</xliff:g>)が <xliff:g id="APP_LABEL">%3$s</xliff:g> で再生中"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g>/<xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"再生"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"一時停止"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"前のトラック"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"次のトラック"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"再生"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> を開く"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="SONG_NAME">%1$s</xliff:g>(アーティスト名: <xliff:g id="ARTIST_NAME">%2$s</xliff:g>)を <xliff:g id="APP_LABEL">%3$s</xliff:g> で再生"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="SONG_NAME">%1$s</xliff:g> を <xliff:g id="APP_LABEL">%2$s</xliff:g> で再生"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"元に戻す"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"<xliff:g id="DEVICENAME">%1$s</xliff:g>で再生するにはもっと近づけてください"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"<xliff:g id="DEVICENAME">%1$s</xliff:g>で再生しています"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"無効: アプリをご確認ください"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"見つかりませんでした"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"コントロールを使用できません"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"選択したデバイス: 1 台"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"選択したデバイス: <xliff:g id="COUNT">%1$d</xliff:g> 台"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(接続解除済み)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"接続できませんでした。もう一度お試しください。"</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"切り替えられません。タップしてやり直してください。"</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"新しいデバイスとのペア設定"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"ビルド番号"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"ビルド番号をクリップボードにコピーしました。"</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"すべて表示"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ネットワークを変更するにはイーサネット接続を解除してください"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"デバイスの機能向上のため、アプリやサービスは、Wi-Fi が OFF の場合でも、いつでも Wi-Fi ネットワークをスキャンできます。この設定は Wi-Fi スキャンの設定で変更できます。"<annotation id="link">"変更"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"機内モードを OFF にする"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"ユーザーの選択"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"バックグラウンドで実行中のアプリ"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"停止"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ja/tiles_states_strings.xml b/packages/SystemUI/res/values-ja/tiles_states_strings.xml
index b65d2f8..7fc9c08c 100644
--- a/packages/SystemUI/res/values-ja/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ja/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"OFF"</item>
     <item msgid="460891964396502657">"ON"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"使用不可"</item>
+    <item msgid="5581384648880018330">"OFF"</item>
+    <item msgid="8000850843692192257">"ON"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 9ab002a..08adb0f 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"მოწყობილობები მიუწვდომელია"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi-Fi არ არის დაკავშირებული"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"განათება"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"ფერების შებრუნება"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"ფერთა ინვერსია"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"დამატებითი პარამეტრები"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"მომხმარებლის პარამეტრები"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"დასრულდა"</string>
@@ -747,7 +747,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="5217151214439341902">"შეეხეთ მარტივი წვდომის ფუნქციების გასახსნელად. მოარგეთ ან შეცვალეთ ეს ღილაკი პარამეტრებში.\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>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"ზევით და მარჯვნივ გადატანა"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"პარამეტრები"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g>, <xliff:g id="ARTIST_NAME">%2$s</xliff:g>, უკრავს <xliff:g id="APP_LABEL">%3$s</xliff:g>-დან"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="TOTAL_TIME">%2$s</xliff:g>-დან <xliff:g id="ELAPSED_TIME">%1$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"დაკვრა"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"პაუზა"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"წინა ჩანაწერი"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"შემდეგი ჩანაწერი"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"დაკვრა"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"გახსენით <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"დაუკარით <xliff:g id="SONG_NAME">%1$s</xliff:g>, <xliff:g id="ARTIST_NAME">%2$s</xliff:g>, <xliff:g id="APP_LABEL">%3$s</xliff:g>-დან"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"დაუკარით <xliff:g id="SONG_NAME">%1$s</xliff:g> <xliff:g id="APP_LABEL">%2$s</xliff:g>-დან"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"მოქმედების გაუქმება"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"მიიტანეტ უფრო ახლოს, რომ დაუკრათ <xliff:g id="DEVICENAME">%1$s</xliff:g>-ზე"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"მიმდინარეობს დაკვრა <xliff:g id="DEVICENAME">%1$s</xliff:g>-ზე"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"არააქტიურია, გადაამოწმეთ აპი"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"ვერ მოიძებნა"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"კონტროლი მიუწვდომელია"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"არჩეულია 1 მოწყობილობა"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"არჩეულია <xliff:g id="COUNT">%1$d</xliff:g> მოწყობილობა"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(კავშირი გაწყვეტილია)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"დაკავშირება ვერ მოხერხდა. ცადეთ ხელახლა."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"ვერ გადაირთო. შეეხეთ ხელახლა საცდელად."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"ახალი მოწყობილობის დაწყვილება"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"ანაწყობის ნომერი"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"ანაწყობის ნომერი დაკოპირებულია გაცვლის ბუფერში."</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"ყველას ნახვა"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ქსელების გადასართავად, გაწყვიტეთ Ethernet-თან კავშირი"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"მოწყობილობისგან მიღებული გამოცდილების გასაუმჯობესებლად, აპებსა და სერვისებს მაინც შეუძლია სკანირება Wi‑Fi ქსელების აღმოსაჩენად, ნებისმიერ დროს, მაშინაც კი, როცა Wi‑Fi გამორთულია. ამის შეცვლა Wi-Fi სკანირების პარამეტრებში შეგიძლიათ. "<annotation id="link">"შეცვლა"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"თვითმფრინავის რეჟიმის გამორთვა"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"მომხმარებლის არჩევა"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"ფონურად მომუშავე აპები"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"შეწყვეტა"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ka/tiles_states_strings.xml b/packages/SystemUI/res/values-ka/tiles_states_strings.xml
index 4e621a0..40dfd39 100644
--- a/packages/SystemUI/res/values-ka/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ka/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"გამორთვა"</item>
     <item msgid="460891964396502657">"ჩართვა"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"მიუწვდომელია"</item>
+    <item msgid="5581384648880018330">"გამორთულია"</item>
+    <item msgid="8000850843692192257">"ჩართულია"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 623d329..ffdde5b 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Құрылғылар қол жетімді емес"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi-Fi желісіне жалғанбаған"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Жарықтығы"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Түс инверсиясы"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Түс инверсиясы"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"Қосымша параметрлер"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Пайдаланушы параметрлері"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"Дайын"</string>
@@ -747,7 +747,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="5217151214439341902">"Арнайы мүмкіндікті ашу үшін түртіңіз. Түймені параметрден реттеңіз не ауыстырыңыз.\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>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Жоғарғы оң жаққа жылжыту"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Параметрлер"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g> қолданбасында <xliff:g id="ARTIST_NAME">%2$s</xliff:g> орындайтын \"<xliff:g id="SONG_NAME">%1$s</xliff:g>\" әні ойнатылуда."</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="TOTAL_TIME">%2$s</xliff:g>/<xliff:g id="ELAPSED_TIME">%1$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"Ойнату"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"Кідірту"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"Алдыңғы трек"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"Келесі трек"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Ойнату"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> қолданбасын ашу"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="APP_LABEL">%3$s</xliff:g> қолданбасында <xliff:g id="ARTIST_NAME">%2$s</xliff:g> орындайтын \"<xliff:g id="SONG_NAME">%1$s</xliff:g>\" әнін ойнату"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="APP_LABEL">%2$s</xliff:g> қолданбасында \"<xliff:g id="SONG_NAME">%1$s</xliff:g>\" әнін ойнату"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"Қайтару"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"<xliff:g id="DEVICENAME">%1$s</xliff:g> құрылғысында музыка ойнату үшін оған жақындаңыз."</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"<xliff:g id="DEVICENAME">%1$s</xliff:g> құрылғысында ойнатылуда."</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Өшірулі. Қолданба тексеріңіз."</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Табылмады"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Басқару виджеті қолжетімсіз"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 құрылғы таңдалды."</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> құрылғы таңдалды."</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(ажыратулы)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Қосылмады. Қайта қосылып көріңіз."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Ауысу мүмкін емес. Әрекетті қайталау үшін түртіңіз."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Жаңа құрылғымен жұптау"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Құрама нөмірі"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Құрама нөмірі буферге көшірілді."</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"Барлығын көру"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Желілерді ауыстыру үшін ethernet кабелін ажыратыңыз."</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Құрылғы жұмысын жақсарту үшін қолданбалар мен қызметтер Wi-Fi байланысы өшірулі кезде де Wi-Fi желілерін іздейді. Оны Wi-Fi іздеу параметрлерінен өзгерте аласыз. "<annotation id="link">"Өзгерту"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Ұшақ режимін өшіру"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Пайдаланушыны таңдау"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Фондық режимде жұмыс істеп тұрған қолданбалар"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Тоқтату"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-kk/tiles_states_strings.xml b/packages/SystemUI/res/values-kk/tiles_states_strings.xml
index d3ad572..3e9aefa 100644
--- a/packages/SystemUI/res/values-kk/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-kk/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"Өшірулі"</item>
     <item msgid="460891964396502657">"Қосулы"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"Қолжетімсіз"</item>
+    <item msgid="5581384648880018330">"Өшірулі"</item>
+    <item msgid="8000850843692192257">"Қосулы"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 75f5a0a..02f7550 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -234,7 +234,7 @@
     <string name="quick_settings_location_label" msgid="2621868789013389163">"ទី​តាំង​"</string>
     <string name="quick_settings_camera_label" msgid="5612076679385269339">"ការចូលប្រើ​កាមេរ៉ា"</string>
     <string name="quick_settings_mic_label" msgid="8392773746295266375">"ការចូលប្រើ​មីក្រូហ្វូន"</string>
-    <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"អាចប្រើបាន"</string>
+    <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"អាចចូលប្រើបាន"</string>
     <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"បាន​ទប់ស្កាត់"</string>
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"ឧបករណ៍​មេឌៀ"</string>
     <string name="quick_settings_user_title" msgid="8673045967216204537">"អ្នកប្រើ"</string>
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"មិន​មាន​ឧបករណ៍​ដែល​អាច​ប្រើ​បាន"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"មិនមាន​ការតភ្ជាប់ Wi-Fi ទេ"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"ពន្លឺ"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"ដាក់​​​បញ្ច្រាស​ពណ៌"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"ការបញ្ច្រាស​ពណ៌"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"ការ​កំណត់​ច្រើន​ទៀត"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"ការកំណត់អ្នកប្រើប្រាស់"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"រួចរាល់"</string>
@@ -747,7 +747,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="5217151214439341902">"ចុចដើម្បីបើក​មុខងារ​ភាពងាយស្រួល។ ប្ដូរ ឬប្ដូរ​ប៊ូតុងនេះ​តាមបំណង​នៅក្នុង​ការកំណត់។\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>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"ផ្លាស់ទីទៅខាងលើផ្នែកខាងស្ដាំ"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"ការកំណត់"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> ច្រៀងដោយ <xliff:g id="ARTIST_NAME">%2$s</xliff:g> កំពុងចាក់ពី <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> នៃ <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"ចាក់"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"ផ្អាក"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"ចម្រៀងមុន"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"ចម្រៀង​បន្ទាប់"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"ចាក់"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"បើក <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"ចាក់ <xliff:g id="SONG_NAME">%1$s</xliff:g> ច្រៀងដោយ <xliff:g id="ARTIST_NAME">%2$s</xliff:g> ពី <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"ចាក់ <xliff:g id="SONG_NAME">%1$s</xliff:g> ពី <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"ត្រឡប់វិញ"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"រំកិលឱ្យកាន់តែជិត ដើម្បីចាក់នៅលើ <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"កំពុង​ចាក់​​នៅ​លើ <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"អសកម្ម ពិនិត្យមើល​កម្មវិធី"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"រកមិន​ឃើញទេ"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"មិនអាច​គ្រប់គ្រង​បានទេ"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"បានជ្រើសរើស​ឧបករណ៍ 1"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"បានជ្រើសរើស​ឧបករណ៍ <xliff:g id="COUNT">%1$d</xliff:g>"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(បាន​ដាច់)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"មិន​អាច​ភ្ជាប់​បាន​ទេ។ សូមព្យាយាមម្ដងទៀត។"</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"មិនអាចប្ដូរបានទេ។ សូមចុចដើម្បី​ព្យាយាម​ម្ដងទៀត។"</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"ផ្គូផ្គង​ឧបករណ៍ថ្មី"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"លេខ​កំណែបង្កើត"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"បានចម្លងលេខ​កំណែបង្កើតទៅឃ្លីបបត។"</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"មើលទាំងអស់"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ដើម្បី​ប្ដូរ​បណ្ដាញ សូមផ្ដាច់​អ៊ីសឺរណិត"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"ដើម្បីធ្វើឱ្យ​បទពិសោធន៍ប្រើប្រាស់​ឧបករណ៍ប្រសើរឡើង កម្មវិធី និងសេវាកម្ម​នៅតែអាចស្កេនរក​បណ្ដាញ Wi‑Fi បានគ្រប់ពេល ទោះបីជា​នៅពេលដែលបិទ Wi‑Fi ក៏ដោយ។ អ្នកអាចប្ដូរវាបាន​នៅក្នុង​ការកំណត់​ការស្កេន Wi‑Fi។ "<annotation id="link">"ប្ដូរ"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"បិទមុខងារពេល​ជិះ​យន្តហោះ"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"ជ្រើសរើសអ្នកប្រើប្រាស់"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"កម្មវិធីដែលកំពុងដំណើរការ​នៅផ្ទៃខាងក្រោយ"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"ឈប់"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-km/tiles_states_strings.xml b/packages/SystemUI/res/values-km/tiles_states_strings.xml
index f67aafb..32a6e22 100644
--- a/packages/SystemUI/res/values-km/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-km/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"បិទ"</item>
     <item msgid="460891964396502657">"បើក"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"មិនមានទេ"</item>
+    <item msgid="5581384648880018330">"បិទ"</item>
+    <item msgid="8000850843692192257">"បើក"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index ce594f7..b29b0bb 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"ಯಾವುದೇ ಸಾಧನಗಳು ಲಭ್ಯವಿಲ್ಲ"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"ವೈ-ಫೈ ಸಂಪರ್ಕಗೊಂಡಿಲ್ಲ"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"ಪ್ರಕಾಶಮಾನ"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"ಬಣ್ಣ ಇನ್ವರ್ಟ್ ಮಾಡಿ"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"ಕಲರ್ ಇನ್‍ವರ್ಶನ್"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"ಹೆಚ್ಚಿನ ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"ಬಳಕೆದಾರರ ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"ಮುಗಿದಿದೆ"</string>
@@ -747,7 +747,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="5217151214439341902">"ಪ್ರವೇಶಿಸುವಿಕೆ ವೈಶಿಷ್ಟ್ಯಗಳನ್ನು ತೆರೆಯಲು ಟ್ಯಾಪ್ ಮಾಡಿ. ಸೆಟ್ಟಿಂಗ್‌ಗಳಲ್ಲಿ ಈ ಬಟನ್ ಅನ್ನು ಕಸ್ಟಮೈಸ್ ಮಾಡಿ ಅಥವಾ ಬದಲಾಯಿಸಿ.\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>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"ಬಲ ಮೇಲ್ಭಾಗಕ್ಕೆ ಸರಿಸಿ"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> ಅವರ <xliff:g id="SONG_NAME">%1$s</xliff:g> ಹಾಡನ್ನು <xliff:g id="APP_LABEL">%3$s</xliff:g> ನಲ್ಲಿ ಪ್ಲೇ ಮಾಡಲಾಗುತ್ತಿದೆ"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="TOTAL_TIME">%2$s</xliff:g> ರಲ್ಲಿ <xliff:g id="ELAPSED_TIME">%1$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"ಪ್ಲೇ ಮಾಡಿ"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"ವಿರಾಮಗೊಳಿಸಿ"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"ಹಿಂದಿನ ಟ್ರ್ಯಾಕ್"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"ಮುಂದಿನ ಟ್ರ್ಯಾಕ್"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"ಪ್ಲೇ ಮಾಡಿ"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> ಅನ್ನು ತೆರೆಯಿರಿ"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> ಅವರ <xliff:g id="SONG_NAME">%1$s</xliff:g> ಹಾಡನ್ನು <xliff:g id="APP_LABEL">%3$s</xliff:g> ನಲ್ಲಿ ಪ್ಲೇ ಮಾಡಿ"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="SONG_NAME">%1$s</xliff:g> ಹಾಡನ್ನು <xliff:g id="APP_LABEL">%2$s</xliff:g> ನಲ್ಲಿ ಪ್ಲೇ ಮಾಡಿ"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"ರದ್ದುಗೊಳಿಸಿ"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"<xliff:g id="DEVICENAME">%1$s</xliff:g> ನಲ್ಲಿ ಪ್ಲೇ ಮಾಡಲು ಅದರ ಹತ್ತಿರಕ್ಕೆ ಸರಿಯಿರಿ"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"<xliff:g id="DEVICENAME">%1$s</xliff:g> ನಲ್ಲಿ ಪ್ಲೇ ಆಗುತ್ತಿದೆ"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"ನಿಷ್ಕ್ರಿಯ, ಆ್ಯಪ್ ಪರಿಶೀಲಿಸಿ"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"ಕಂಡುಬಂದಿಲ್ಲ"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"ನಿಯಂತ್ರಣ ಲಭ್ಯವಿಲ್ಲ"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 ಸಾಧನವನ್ನು ಆಯ್ಕೆ ಮಾಡಲಾಗಿದೆ"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> ಸಾಧನಗಳನ್ನು ಆಯ್ಕೆ ಮಾಡಲಾಗಿದೆ"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(ಡಿಸ್‌ಕನೆಕ್ಟ್ ಆಗಿದೆ)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"ಸಂಪರ್ಕಿಸಲು ಸಾಧ್ಯವಾಗುತ್ತಿಲ್ಲ. ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"ಬದಲಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ. ಪುನಃ ಪ್ರಯತ್ನಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"ಹೊಸ ಸಾಧನವನ್ನು ಜೋಡಿಸಿ"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"ಬಿಲ್ಡ್ ಸಂಖ್ಯೆ"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"ಬಿಲ್ಡ್ ಸಂಖ್ಯೆಯನ್ನು ಕ್ಲಿಪ್‌ಬೋರ್ಡ್‌ನಲ್ಲಿ ನಕಲಿಸಲಾಗಿದೆ."</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"ಎಲ್ಲವನ್ನೂ ನೋಡಿ"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ನೆಟ್‌ವರ್ಕ್‌ಗಳನ್ನು ಬದಲಿಸಲು, ಇಥರ್ನೆಟ್ ಅನ್ನು ಡಿಸ್‌ಕನೆಕ್ಟ್ ಮಾಡಿ"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"ವೈ-ಫೈ ಆಫ್ ಇದ್ದಾಗಲೂ ಸಹ, ಸಾಧನದ ಅನುಭವವನ್ನು ಸುಧಾರಿಸಲು, ಆ್ಯಪ್‌ಗಳು ಮತ್ತು ಸೇವೆಗಳು ಯಾವಾಗ ಬೇಕಾದರೂ ಸಹ ವೈ-ಫೈ ನೆಟ್‌ವರ್ಕ್‌ಗಳಿಗಾಗಿ ಸ್ಕ್ಯಾನ್ ಮಾಡಬಹುದು. ನೀವು ಇದನ್ನು ವೈ-ಫೈ ಸ್ಕ್ಯಾನಿಂಗ್ ಸೆಟ್ಟಿಂಗ್‌ಗಳಲ್ಲಿ ಬದಲಾಯಿಸಬಹುದು. "<annotation id="link">"ಬದಲಿಸಿ"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"ಏರ್‌ಪ್ಲೇನ್ ಮೋಡ್ ಆಫ್ ಮಾಡಿ"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"ಬಳಕೆದಾರ ಆಯ್ಕೆಮಾಡಿ"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"ಹಿನ್ನೆಲೆಯಲ್ಲಿ ರನ್ ಆಗುತ್ತಿರುವ ಆ್ಯಪ್‌ಗಳು"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"ನಿಲ್ಲಿಸಿ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-kn/tiles_states_strings.xml b/packages/SystemUI/res/values-kn/tiles_states_strings.xml
index 26ec958..c13e198 100644
--- a/packages/SystemUI/res/values-kn/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-kn/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"ಆಫ್ ಮಾಡಿ"</item>
     <item msgid="460891964396502657">"ಆನ್ ಮಾಡಿ"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"ಲಭ್ಯವಿಲ್ಲ"</item>
+    <item msgid="5581384648880018330">"ಆಫ್ ಆಗಿದೆ"</item>
+    <item msgid="8000850843692192257">"ಆನ್ ಆಗಿದೆ"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index e742659..b5f2ad3 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"사용 가능한 기기가 없습니다."</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi-Fi가 연결되지 않음"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"밝기"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"색상 반전"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"색상 반전"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"설정 더보기"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"사용자 설정"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"완료"</string>
@@ -747,7 +747,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="5217151214439341902">"접근성 기능을 열려면 탭하세요. 설정에서 이 버튼을 맞춤설정하거나 교체할 수 있습니다.\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>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"오른쪽 상단으로 이동"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"설정"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g>에서 <xliff:g id="ARTIST_NAME">%2$s</xliff:g>의 <xliff:g id="SONG_NAME">%1$s</xliff:g> 재생 중"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g>/<xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"재생"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"일시중지"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"이전 트랙"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"다음 트랙"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"재생"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> 열기"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="APP_LABEL">%3$s</xliff:g>에서 <xliff:g id="ARTIST_NAME">%2$s</xliff:g>의 <xliff:g id="SONG_NAME">%1$s</xliff:g> 재생"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="APP_LABEL">%2$s</xliff:g>에서 <xliff:g id="SONG_NAME">%1$s</xliff:g> 재생"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"실행취소"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"<xliff:g id="DEVICENAME">%1$s</xliff:g>에서 재생하려면 기기를 더 가까이로 옮기세요."</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"<xliff:g id="DEVICENAME">%1$s</xliff:g>에서 재생 중"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"비활성. 앱을 확인하세요."</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"찾을 수 없음"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"컨트롤을 사용할 수 없음"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"기기 1대 선택됨"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"기기 <xliff:g id="COUNT">%1$d</xliff:g>대 선택됨"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(연결 끊김)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"연결할 수 없습니다. 다시 시도하세요."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"전환할 수 없습니다. 다시 시도하려면 탭하세요."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"새 기기와 페어링"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"빌드 번호"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"빌드 번호가 클립보드에 복사되었습니다."</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"모두 보기"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"네트워크를 전환하려면 이더넷을 연결 해제하세요."</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"기기 환경을 개선하기 위해 Wi‑Fi가 꺼져 있을 때도 앱과 서비스에서 Wi‑Fi 네트워크를 검색할 수 있습니다. 이 설정은 Wi‑Fi 검색 설정에서 변경할 수 있습니다. "<annotation id="link">"변경"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"비행기 모드 사용 중지"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"사용자 선택"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"백그라운드에서 실행 중인 앱"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"중지"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ko/tiles_states_strings.xml b/packages/SystemUI/res/values-ko/tiles_states_strings.xml
index 0c22971..28d45cf 100644
--- a/packages/SystemUI/res/values-ko/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ko/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"꺼짐"</item>
     <item msgid="460891964396502657">"켜짐"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"사용 불가"</item>
+    <item msgid="5581384648880018330">"사용 중지됨"</item>
+    <item msgid="8000850843692192257">"사용 설정됨"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index f6fe747..2d2f1cf 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Жеткиликтүү түзмөктөр жок"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi-Fi туташкан жок"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Жарыктыгы"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Түстөрдү инверсиялоо"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Түстү инверсиялоо"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"Дагы жөндөөлөр"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Колдонуучунун жөндөөлөрү"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"Бүттү"</string>
@@ -747,7 +747,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="5217151214439341902">"Атайын мүмкүнчүлүктөрдү ачуу үчүн басыңыз. Бул баскычты Жөндөөлөрдөн өзгөртүңүз.\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>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Жогорку оң жакка жылдырыңыз"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Жөндөөлөр"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> ыры (аткаруучу: <xliff:g id="ARTIST_NAME">%2$s</xliff:g>) <xliff:g id="APP_LABEL">%3$s</xliff:g> колдонмосунан ойнотулуп жатат"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="TOTAL_TIME">%2$s</xliff:g> ичинен <xliff:g id="ELAPSED_TIME">%1$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"Ойнотуу"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"Тындыруу"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"Мурунку трек"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"Кийинки трек"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Ойнотуу"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> колдонмосун ачуу"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="SONG_NAME">%1$s</xliff:g> ырын (аткаруучу: <xliff:g id="ARTIST_NAME">%2$s</xliff:g>) <xliff:g id="APP_LABEL">%3$s</xliff:g> колдонмосунан ойнотуу"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="SONG_NAME">%1$s</xliff:g> ырын <xliff:g id="APP_LABEL">%2$s</xliff:g> колдонмосунан ойнотуу"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"Кайтаруу"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"<xliff:g id="DEVICENAME">%1$s</xliff:g> түзмөгүндө ойнотуу үчүн жакыныраак жылдырыңыз"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"<xliff:g id="DEVICENAME">%1$s</xliff:g> аркылуу ойнотулууда"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Жигерсиз. Колдонмону текшериңиз"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Табылган жок"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Башкара албайсыз"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 түзмөк тандалды"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> түзмөк тандалды"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(ажыратылды)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Байланышпай койду. Кайталоо."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Которулбай жатат. Кайталоо үчүн басыңыз."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Жаңы түзмөктү жупташтыруу"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Курама номери"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Курама номери алмашуу буферине көчүрүлдү."</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"Баарын көрүү"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Башка тармактарга которулуу үчүн Ethernet кабелин ажыратыңыз"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Түзмөктүн колдонулушун жакшыртуу үчүн колдонмолор менен кызматтар Wi‑Fi өчүп турса да зымсыз тармактарды издей беришет. Аны Wi-Fi тармактарын издөө жөндөөлөрүнөн өзгөртө аласыз. "<annotation id="link">"Өзгөртүү"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Учак режимин өчүрүү"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Колдонуучуну тандоо"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Фондо иштеп жаткан колдонмолор"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Токтотуу"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ky/tiles_states_strings.xml b/packages/SystemUI/res/values-ky/tiles_states_strings.xml
index ae6520e..139d784 100644
--- a/packages/SystemUI/res/values-ky/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ky/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"Өчүк"</item>
     <item msgid="460891964396502657">"Күйүк"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"Жеткиликсиз"</item>
+    <item msgid="5581384648880018330">"Өчүк"</item>
+    <item msgid="8000850843692192257">"Күйүк"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index c401823..6903250 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"​ບໍ່​ມີ​ອຸ​ປະ​ກອນ​ທີ່​ສາ​ມາດ​ໃຊ້​ໄດ້"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"ບໍ່ໄດ້ເຊື່ອມຕໍ່ Wi-Fi"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"ຄວາມແຈ້ງ"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"ສະຫຼັບສີ"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"ການປີ້ນສີ"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"​ການ​ຕັ້ງ​ຄ່າ​ເພີ່ມ​ເຕີມ"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"ຕັ້ງຄ່າຜູ້ໃຊ້"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"ແລ້ວໆ"</string>
@@ -747,7 +747,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="5217151214439341902">"ແຕະເພື່ອເປີດຄຸນສົມບັດການຊ່ວຍເຂົ້າເຖິງ. ປັບແຕ່ງ ຫຼື ປ່ຽນປຸ່ມນີ້ໃນການຕັ້ງຄ່າ.\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>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"ຍ້າຍຂວາເທິງ"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"ການຕັ້ງຄ່າ"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> ໂດຍ <xliff:g id="ARTIST_NAME">%2$s</xliff:g> ກຳລັງຫຼິ້ນຈາກ <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> ຈາກ <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"ຫຼິ້ນ"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"ຢຸດຊົ່ວຄາວ"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"ເພງກ່ອນໜ້າ"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"ເພງຕໍ່ໄປ"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"ຫຼິ້ນ"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"ເປີດ <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"ຫຼິ້ນ <xliff:g id="SONG_NAME">%1$s</xliff:g> ໂດຍ <xliff:g id="ARTIST_NAME">%2$s</xliff:g> ຈາກ <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"ຫຼິ້ນ <xliff:g id="SONG_NAME">%1$s</xliff:g> ຈາກ <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"ຍົກເລີກ"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"ຍ້າຍໄປໃກ້ຂຶ້ນເພື່ອຫຼິ້ນຢູ່ <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"ກຳລັງຫຼິ້ນຢູ່ <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"ບໍ່ເຮັດວຽກ, ກະລຸນາກວດສອບແອັບ"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"ບໍ່ພົບ"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"ບໍ່ສາມາດໃຊ້ການຄວບຄຸມໄດ້"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"ເລືອກ 1 ອຸປະກອນແລ້ວ"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"ເລືອກ <xliff:g id="COUNT">%1$d</xliff:g> ອຸປະກອນແລ້ວ"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(ຕັດການເຊື່ອມຕໍ່ແລ້ວ)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"ບໍ່ສາມາດເຊື່ອມຕໍ່ໄດ້. ລອງໃໝ່."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"ບໍ່ສາມາດສະຫຼັບໄດ້. ແຕະເພື່ອລອງໃໝ່."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"ຈັບຄູ່ອຸປະກອນໃໝ່"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"ໝາຍເລກສ້າງ"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"ສຳເນົາໝາຍເລກສ້າງໄປໃສ່ຄລິບບອດແລ້ວ."</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"ເບິ່ງທັງໝົດ"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ເພື່ອສະຫຼັບເຄືອຂ່າຍ, ໃຫ້ຕັດການເຊື່ອມຕໍ່ອີເທີເນັດກ່ອນ"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"ເພື່ອປັບປຸງປະສົບການອຸປະກອນ, ແອັບ ແລະ ບໍລິການຍັງຄົງສາມາດສະແກນຫາເຄືອຂ່າຍ Wi‑Fi ຕອນໃດກໍໄດ້, ເຖິງແມ່ນວ່າຈະປິດ Wi‑Fi ໄວ້ກໍຕາມ. ທ່ານສາມາດປ່ຽນສິ່ງນີ້ໄດ້ໃນການຕັ້ງຄ່າການສະແກນ Wi‑Fi. "<annotation id="link">"ປ່ຽນ"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"ປິດໂໝດຢູ່ໃນຍົນ"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"ເລືອກຜູ້ໃຊ້"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"ແອັບທີ່ກຳລັງເອີ້ນໃຊ້ໃນພື້ນຫຼັງ"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"ຢຸດ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lo/tiles_states_strings.xml b/packages/SystemUI/res/values-lo/tiles_states_strings.xml
index e818a09..74c0f24 100644
--- a/packages/SystemUI/res/values-lo/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-lo/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"ປິດ"</item>
     <item msgid="460891964396502657">"ເປີດ"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"ບໍ່ສາມາດໃຊ້ໄດ້"</item>
+    <item msgid="5581384648880018330">"ປິດ"</item>
+    <item msgid="8000850843692192257">"ເປີດ"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 2670ce4..b8c8a4a 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -252,7 +252,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Nėra pasiekiamų įrenginių"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"„Wi-Fi“ neprijungtas"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Šviesumas"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Pakeisti spalvas"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Spalvų inversija"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"Daugiau nustatymų"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Naudotojo nustatymai"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"Atlikta"</string>
@@ -757,7 +757,7 @@
     <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Viso ekrano didinimas"</string>
     <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Didinti ekrano dalį"</string>
     <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Perjungti"</string>
-    <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Pritaikomumo gestas pakeistas pritaikomumo mygtuku\n\n"<annotation id="link">"Žr. nustatymus"</annotation></string>
+    <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Palietę atidarykite pritaikymo neįgaliesiems funkcijas. Tinkinkite arba pakeiskite šį mygtuką nustatymuose.\n\n"<annotation id="link">"Žr. nustatymus"</annotation></string>
     <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Perkelkite mygtuką prie krašto, kad laikinai jį paslėptumėte"</string>
     <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Perkelti į viršų kairėje"</string>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Perkelti į viršų dešinėje"</string>
@@ -810,10 +810,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Nustatymai"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> – „<xliff:g id="SONG_NAME">%1$s</xliff:g>“ leidžiama iš „<xliff:g id="APP_LABEL">%3$s</xliff:g>“"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> iš <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"Paleisti"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"Pristabdyti"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"Ankstesnis takelis"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"Kitas takelis"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Leisti"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Atidaryti „<xliff:g id="APP_LABEL">%1$s</xliff:g>“"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Leisti <xliff:g id="ARTIST_NAME">%2$s</xliff:g> – „<xliff:g id="SONG_NAME">%1$s</xliff:g>“ iš „<xliff:g id="APP_LABEL">%3$s</xliff:g>“"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Leisti „<xliff:g id="SONG_NAME">%1$s</xliff:g>“ iš „<xliff:g id="APP_LABEL">%2$s</xliff:g>“"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"Anuliuoti"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Prieikite arčiau, kad galėtumėte leisti įrenginyje „<xliff:g id="DEVICENAME">%1$s</xliff:g>“"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"Leidžiama įrenginyje „<xliff:g id="DEVICENAME">%1$s</xliff:g>“"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Neaktyvu, patikrinkite progr."</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Nerasta"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Valdiklis nepasiekiamas"</string>
@@ -828,7 +835,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"Pasirinktas 1 įrenginys"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"Pasirinkta įrenginių: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(atjungta)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Nepavyko prijungti. Bandykite dar kartą."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Nepavyko perjungti. Bandykite vėl palietę."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Naujo įrenginio susiejimas"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Versijos numeris"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Versijos numeris nukopijuotas į iškarpinę."</string>
@@ -893,8 +900,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"Žiūrėti viską"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Norėdami perjungti tinklus, atjunkite eternetą"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Kad pagerintų įrenginio funkcijas, programos ir paslaugos vis tiek gali bet kada nuskaityti ieškodamos „Wi‑Fi“ tinklų, net jei „Wi‑Fi“ išjungtas. Tai galite pakeisti „Wi-Fi“ nuskaitymo nustatymuose. "<annotation id="link">"Pakeisti"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Išjungti lėktuvo režimą"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Naudotojo pasirinkimas"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Fone veikiančios programos"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Sustabdyti"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lt/tiles_states_strings.xml b/packages/SystemUI/res/values-lt/tiles_states_strings.xml
index 28d4a73..08e0e6d 100644
--- a/packages/SystemUI/res/values-lt/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-lt/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"Išjungta"</item>
     <item msgid="460891964396502657">"Įjungta"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"Nepasiekiama"</item>
+    <item msgid="5581384648880018330">"Išjungta"</item>
+    <item msgid="8000850843692192257">"Įjungta"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 16e2eef..48715802 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -251,7 +251,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Nav pieejamu ierīču."</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Nav izveidots savienojums ar Wi-Fi"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Spilgtums"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Invertēt krāsas"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Krāsu inversija"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"Vairāk iestatījumu"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Lietotāja iestatījumi"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"Gatavs"</string>
@@ -752,7 +752,7 @@
     <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Palielināt visu ekrānu"</string>
     <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Palielināt ekrāna daļu"</string>
     <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Pārslēgt"</string>
-    <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Pieejamības žests ir aizstāts ar pieejamības pogu\n\n"<annotation id="link">"Skatīt iestatījumus"</annotation></string>
+    <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Atveriet pieejamības funkcijas. Pielāgojiet vai aizstājiet šo pogu iestatījumos.\n\n"<annotation id="link">"Skatīt iestatījumus"</annotation></string>
     <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Lai īslaicīgi paslēptu pogu, pārvietojiet to uz malu"</string>
     <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Pārvietot augšpusē pa kreisi"</string>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Pārvietot augšpusē pa labi"</string>
@@ -804,10 +804,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Iestatījumi"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"Tiek atskaņots fails “<xliff:g id="SONG_NAME">%1$s</xliff:g>” (izpildītājs: <xliff:g id="ARTIST_NAME">%2$s</xliff:g>) no lietotnes <xliff:g id="APP_LABEL">%3$s</xliff:g>."</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> no <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"Atskaņot"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"Apturēt"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"Iepriekšējais ieraksts"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"Nākamais ieraksts"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Atskaņot"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Atveriet lietotni <xliff:g id="APP_LABEL">%1$s</xliff:g>."</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Atskaņojiet failu “<xliff:g id="SONG_NAME">%1$s</xliff:g>” (izpildītājs: <xliff:g id="ARTIST_NAME">%2$s</xliff:g>) no lietotnes <xliff:g id="APP_LABEL">%3$s</xliff:g>."</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Atskaņojiet failu “<xliff:g id="SONG_NAME">%1$s</xliff:g>” no lietotnes <xliff:g id="APP_LABEL">%2$s</xliff:g>."</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"Atsaukt"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Pārvietojiet savu ierīci tuvāk, lai atskaņotu mūziku ierīcē “<xliff:g id="DEVICENAME">%1$s</xliff:g>”"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"Notiek atskaņošana ierīcē “<xliff:g id="DEVICENAME">%1$s</xliff:g>”"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Neaktīva, pārbaudiet lietotni"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Netika atrasta"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Vadīkla nav pieejama"</string>
@@ -822,7 +829,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"Atlasīta viena ierīce"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"Atlasītas vairākas ierīces (kopā <xliff:g id="COUNT">%1$d</xliff:g>)"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(savienojums pārtraukts)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Nevarēja izveidot savienojumu. Mēģiniet vēlreiz."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Nevar pārslēgt. Pieskarieties, lai mēģinātu vēlreiz."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Savienošana pārī ar jaunu ierīci"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Versijas numurs"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Versijas numurs ir kopēts starpliktuvē."</string>
@@ -887,8 +894,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"Visu tīklu skatīšana"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Lai pārslēgtu tīklus, atvienojiet tīkla Ethernet vadu."</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Lai uzlabotu ierīces lietošanas iespējas, lietotnes un pakalpojumi joprojām varēs meklēt Wi‑Fi tīklus jebkurā laikā, pat ja Wi‑Fi būs izslēgts. Varat to mainīt Wi‑Fi meklēšanas iestatījumos. "<annotation id="link">"Mainīt"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Izslēgt lidojuma režīmu"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Lietotāja atlase"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Lietotnes, kas darbojas fonā"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Apturēt"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lv/tiles_states_strings.xml b/packages/SystemUI/res/values-lv/tiles_states_strings.xml
index ed0baf2..c5718f8 100644
--- a/packages/SystemUI/res/values-lv/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-lv/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"Izslēgts"</item>
     <item msgid="460891964396502657">"Ieslēgts"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"Nav pieejams"</item>
+    <item msgid="5581384648880018330">"Izslēgts"</item>
+    <item msgid="8000850843692192257">"Ieslēgts"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index de05345..ae9f3c0 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Нема достапни уреди"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi-Fi не е поврзано"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Осветленост"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Преврти ги боите"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Инверзија на боите"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"Повеќе поставки"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Поставки на корисникот"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"Готово"</string>
@@ -747,7 +747,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="5217151214439341902">"Допрете за функциите за пристапност. Приспособете или заменете го копчево во „Поставки“.\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>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Премести горе десно"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Поставки"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> од <xliff:g id="ARTIST_NAME">%2$s</xliff:g> е пуштено на <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> од <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"Пушти"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"Пауза"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"Претходна песна"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"Следна песна"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Пушти"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Отворете <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Пуштете <xliff:g id="SONG_NAME">%1$s</xliff:g> од <xliff:g id="ARTIST_NAME">%2$s</xliff:g> на <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Пуштете <xliff:g id="SONG_NAME">%1$s</xliff:g> на <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"Врати"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Приближете се за да пуштите на <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"Се репродуцира на <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Неактивна, провери апликација"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Не е најдено"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Контролата не е достапна"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"Избран е 1 уред"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"Избрани се <xliff:g id="COUNT">%1$d</xliff:g> уреди"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(врската е прекината)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Не може да се поврзе. Обидете се повторно."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Не се префрла. Допрете и обидете се пак."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Спарете нов уред"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Број на верзија"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Бројот на верзијата е копиран во привремената меморија."</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"Прикажи ги сите"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"За промена на мрежата, прекинете ја врската со етернетот"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"За да се подобри доживувањето на уредот, апликациите и услугите може сѐ уште да скенираат за Wi‑Fi мрежи во секое време, дури и кога Wi‑Fi е исклучено. Може да го промените ова во поставките за „Скенирање за Wi-Fi“. "<annotation id="link">"Промени"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Исклучи го авионскиот режим"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Изберете корисник"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Апликации се извршуваат во заднина"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Крај"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-mk/tiles_states_strings.xml b/packages/SystemUI/res/values-mk/tiles_states_strings.xml
index 5c36715..fa484ae 100644
--- a/packages/SystemUI/res/values-mk/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-mk/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"Исклучен"</item>
     <item msgid="460891964396502657">"Вклучен"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"Недостапно"</item>
+    <item msgid="5581384648880018330">"Исклучено"</item>
+    <item msgid="8000850843692192257">"Вклучено"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index e7a5c33..ea54bd0 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"ഉപകരണങ്ങളൊന്നും ലഭ്യമല്ല"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"വൈഫൈ കണക്റ്റ് ചെയ്‌തിട്ടില്ല"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"തെളിച്ചം"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"നെഗറ്റീവ് ലുക്ക്"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"നിറം വിപരീതമാക്കൽ"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"കൂടുതൽ ക്രമീകരണങ്ങൾ"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"ഉപയോക്തൃ ക്രമീകരണം"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"പൂർത്തിയാക്കി"</string>
@@ -747,7 +747,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="5217151214439341902">"ഉപയോഗസഹായി ഫീച്ചർ തുറക്കാൻ ടാപ്പ് ചെയ്യൂ. ക്രമീകരണത്തിൽ ഈ ബട്ടൺ ഇഷ്ടാനുസൃതമാക്കാം, മാറ്റാം.\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>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"മുകളിൽ വലതുഭാഗത്തേക്ക് നീക്കുക"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"ക്രമീകരണം"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> എന്ന ആർട്ടിസ്റ്റിന്റെ <xliff:g id="SONG_NAME">%1$s</xliff:g> എന്ന ഗാനം <xliff:g id="APP_LABEL">%3$s</xliff:g> ആപ്പിൽ പ്ലേ ചെയ്യുന്നു"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="TOTAL_TIME">%2$s</xliff:g>-ൽ <xliff:g id="ELAPSED_TIME">%1$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"പ്ലേ ചെയ്യുക"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"താൽക്കാലികമായി നിർത്തുക"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"മുമ്പത്തെ ട്രാക്ക്"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"അടുത്ത ട്രാക്ക്"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"പ്ലേ ചെയ്യുക"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> തുറക്കുക"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> എന്ന ആർട്ടിസ്റ്റിന്റെ <xliff:g id="SONG_NAME">%1$s</xliff:g> എന്ന ഗാനം <xliff:g id="APP_LABEL">%3$s</xliff:g> ആപ്പിൽ പ്ലേ ചെയ്യുക"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="SONG_NAME">%1$s</xliff:g> എന്ന ഗാനം <xliff:g id="APP_LABEL">%2$s</xliff:g> ആപ്പിൽ പ്ലേ ചെയ്യുക"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"പഴയപടിയാക്കുക"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"<xliff:g id="DEVICENAME">%1$s</xliff:g> എന്നതിൽ പ്ലേ ചെയ്യാൻ അടുത്തേക്ക് നീക്കുക"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"<xliff:g id="DEVICENAME">%1$s</xliff:g> എന്നതിൽ പ്ലേ ചെയ്യുന്നു"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"നിഷ്‌ക്രിയം, ആപ്പ് പരിശോധിക്കൂ"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"കണ്ടെത്തിയില്ല"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"നിയന്ത്രണം ലഭ്യമല്ല"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"ഒരു ഉപകരണം തിരഞ്ഞെടുത്തു"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> ഉപകരണങ്ങൾ തിരഞ്ഞെടുത്തു"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(വിച്ഛേദിച്ചു)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"കണക്റ്റ് ചെയ്യാനായില്ല. വീണ്ടും ശ്രമിക്കുക."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"മാറാനാകുന്നില്ല. വീണ്ടും ശ്രമിക്കാൻ ടാപ്പ് ചെയ്യുക."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"പുതിയ ഉപകരണവുമായി ജോടിയാക്കുക"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"ബിൽഡ് നമ്പർ"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"ക്ലിപ്പ്ബോർഡിലേക്ക് ബിൽഡ് നമ്പർ പകർത്തി."</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"എല്ലാം കാണുക"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"മറ്റ് നെറ്റ്‌വർക്കുകളിലേക്ക് മാറാൻ, ഇതർനെറ്റ് വിച്ഛേദിക്കുക"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"ഉപകരണ അനുഭവം മെച്ചപ്പെടുത്താൻ, വൈഫൈ ഓഫാക്കിയിരിക്കുമ്പോൾ പോലും ആപ്പുകൾക്കും സേവനങ്ങൾക്കും വൈഫൈ നെറ്റ്‌വർക്കുകൾ കണ്ടെത്താൻ ഏത് സമയത്തും സ്‌കാൻ ചെയ്യാനാകും. നിങ്ങൾക്ക് ഇത് വൈഫൈ സ്‌കാനിംഗ് ക്രമീകരണത്തിൽ മാറ്റാം. "<annotation id="link">"മാറ്റുക"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"ഫ്ലൈറ്റ് മോഡ് ഓഫാക്കുക"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"ഉപയോക്താവിനെ തിരഞ്ഞെടുക്കൂ"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"ആപ്പുകൾ പശ്ചാത്തലത്തിൽ റൺ ചെയ്യുന്നു"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"നിർത്തുക"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ml/tiles_states_strings.xml b/packages/SystemUI/res/values-ml/tiles_states_strings.xml
index 5cfd45a..0cca763 100644
--- a/packages/SystemUI/res/values-ml/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ml/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"ഓഫാണ്"</item>
     <item msgid="460891964396502657">"ഓണാണ്"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"ലഭ്യമല്ല"</item>
+    <item msgid="5581384648880018330">"ഓഫാണ്"</item>
+    <item msgid="8000850843692192257">"ഓണാണ്"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index f324cc11..d4c924d 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Төхөөрөмж байхгүй"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi-Fi-д холбогдоогүй байна"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Тодрол"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Өнгийг урвуулах"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Өнгө урвуулах"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"Бусад тохиргоо"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Хэрэглэгчийн тохиргоо"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"Дууссан"</string>
@@ -747,7 +747,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="5217151214439341902">"Хандалтын онцлогуудыг нээхийн тулд товшино уу. Энэ товчлуурыг Тохиргоо хэсэгт өөрчилж эсвэл солиорой.\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>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Баруун дээш зөөх"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Тохиргоо"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g> дээр тоглуулж буй <xliff:g id="ARTIST_NAME">%2$s</xliff:g>-н <xliff:g id="SONG_NAME">%1$s</xliff:g>"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="TOTAL_TIME">%2$s</xliff:g>-н <xliff:g id="ELAPSED_TIME">%1$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"Тоглуулах"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"Түр зогсоох"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"Өмнөх бичлэг"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"Дараагийн бичлэг"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Тоглуулах"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g>-г нээх"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g>-н <xliff:g id="SONG_NAME">%1$s</xliff:g>-г <xliff:g id="APP_LABEL">%3$s</xliff:g> дээр тоглуулах"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="SONG_NAME">%1$s</xliff:g>-г <xliff:g id="APP_LABEL">%2$s</xliff:g> дээр тоглуулах"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"Болих"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"<xliff:g id="DEVICENAME">%1$s</xliff:g> дээр тоглуулахын тулд төхөөрөмжөө ойртуулна уу"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"<xliff:g id="DEVICENAME">%1$s</xliff:g> дээр тоглуулж байна"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Идэвхгүй байна, аппыг шалгана уу"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Олдсонгүй"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Хяналт боломжгүй байна"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 төхөөрөмж сонгосон"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> төхөөрөмж сонгосон"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(салсан)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Холбогдож чадсангүй. Дахин оролдоно уу."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Сэлгэх боломжгүй. Дахин оролдохын тулд товшино уу."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Шинэ төхөөрөмж хослуулах"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Хийцийн дугаар"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Хийцийн дугаарыг түр санах ойд хуулсан."</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"Бүгдийг харах"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Сүлжээг сэлгэхийн тулд этернэтийг салгана уу"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Төхөөрөмжийн туршлагыг сайжруулахын тулд аппууд болон үйлчилгээнүүд нь Wi-Fi сүлжээг хүссэн үедээ буюу Wi-Fi-г унтраалттай байсан ч скан хийх боломжтой хэвээр байна. Та үүнийг Wi-Fi скан хийх тохиргоонд өөрчлөх боломжтой. "<annotation id="link">"Өөрчлөх"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Нислэгийн горимыг унтраах"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Хэрэглэгч сонгох"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Ард ажиллаж байгаа аппууд"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Зогсоох"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-mn/tiles_states_strings.xml b/packages/SystemUI/res/values-mn/tiles_states_strings.xml
index ba14927..41049d8 100644
--- a/packages/SystemUI/res/values-mn/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-mn/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"Унтраалттай"</item>
     <item msgid="460891964396502657">"Асаалттай"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"Боломжгүй"</item>
+    <item msgid="5581384648880018330">"Унтраалттай байна"</item>
+    <item msgid="8000850843692192257">"Асаалттай байна"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index e72d3c1..5b41bed 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"कोणतेही डिव्हाइसेस उपलब्ध नाहीत"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"वाय-फाय नाही"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"चमक"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"रंग उलटे करा"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"कलर इन्व्हर्जन"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"अधिक सेटिंग्ज"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"वापरकर्ता सेटिंग्ज"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"पूर्ण झाले"</string>
@@ -747,7 +747,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="5217151214439341902">"अ‍ॅक्सेसिबिलिटी वैशिष्ट्ये उघडण्यासाठी, टॅप करा. सेटिंग्जमध्ये हे बटण कस्टमाइझ करा किंवा बदला.\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>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"वर उजवीकडे हलवा"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"सेटिंग्ज"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g> मध्ये <xliff:g id="ARTIST_NAME">%2$s</xliff:g> चे <xliff:g id="SONG_NAME">%1$s</xliff:g> प्ले होत आहे"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="TOTAL_TIME">%2$s</xliff:g> पैकी <xliff:g id="ELAPSED_TIME">%1$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"प्ले करा"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"थांबवा"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"मागील गाणे"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"पुढील गाणे"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"प्ले करणे"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> उघडा"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="APP_LABEL">%3$s</xliff:g> मध्ये <xliff:g id="ARTIST_NAME">%2$s</xliff:g> चे <xliff:g id="SONG_NAME">%1$s</xliff:g> प्ले करा"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="APP_LABEL">%2$s</xliff:g> मध्ये <xliff:g id="SONG_NAME">%1$s</xliff:g> प्ले करा"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"पहिल्यासारखे करा"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"<xliff:g id="DEVICENAME">%1$s</xliff:g> वर प्ले करण्यासाठी जवळ जा"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"<xliff:g id="DEVICENAME">%1$s</xliff:g> वर प्ले केला जात आहे"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"निष्क्रिय, ॲप तपासा"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"आढळले नाही"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"नियंत्रण उपलब्ध नाही"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"एक डिव्हाइस निवडले"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> डिव्हाइस निवडली आहेत"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(डिस्कनेक्ट केलेले)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"कनेक्ट करू शकलो नाही. पुन्हा प्रयत्न करा."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"स्विच करू शकत नाही. पुन्हा प्रयत्न करण्यासाठी टॅप करा."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"नवीन डिव्हाइससोबत पेअर करा"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"बिल्ड नंबर"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"बिल्ड नंबर क्लिपबोर्डवर कॉपी केला."</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"सर्व पहा"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"नेटवर्क स्विच करण्यासाठी, इथरनेट केबल डिस्कनेक्ट करा"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"डिव्हाइसच्या अनुभवामध्ये सुधारणा करण्यासाठी, वाय-फाय बंद असले तरीही ॲप्स आणि सेवा या कधीही वाय-फाय नेटवर्क स्कॅन करू शकतात. तुम्ही हे वाय-फाय स्कॅनिंग सेटिंग्जमध्ये बदलू शकता. "<annotation id="link">"बदला"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"विमान मोड बंद करा"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"वापरकर्ता निवडा"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"ॲप्स बॅकग्राउंडमध्ये रन होत आहेत"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"थांबवा"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-mr/tiles_states_strings.xml b/packages/SystemUI/res/values-mr/tiles_states_strings.xml
index dbb7ed5..588c5ad 100644
--- a/packages/SystemUI/res/values-mr/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-mr/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"बंद आहे"</item>
     <item msgid="460891964396502657">"सुरू आहे"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"उपलब्ध नाही"</item>
+    <item msgid="5581384648880018330">"बंद आहे"</item>
+    <item msgid="8000850843692192257">"सुरू आहे"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 09b8241..1dc3873 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Tiada peranti tersedia"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi-Fi tidak disambungkan"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Kecerahan"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Songsangkan warna"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Penyongsangan warna"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"Lagi tetapan"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Tetapan pengguna"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"Selesai"</string>
@@ -747,7 +747,7 @@
     <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Besarkan skrin penuh"</string>
     <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Besarkan sebahagian skrin"</string>
     <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Tukar"</string>
-    <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Butang kebolehaksesan menggantikan gerak isyarat kebolehaksesan\n\n"<annotation id="link">"Lihat tetapan"</annotation></string>
+    <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Ketik untuk membuka ciri kebolehaksesan. Sesuaikan/gantikan butang ini dalam Tetapan.\n\n"<annotation id="link">"Lihat tetapan"</annotation></string>
     <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Gerakkan butang ke tepi untuk disembunyikan buat sementara waktu"</string>
     <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Alihkan ke atas sebelah kiri"</string>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Alihkan ke atas sebelah kanan"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Tetapan"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> oleh <xliff:g id="ARTIST_NAME">%2$s</xliff:g> dimainkan daripada <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> daripada <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"Main"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"Jeda"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"Lagu sebelumnya"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"Lagu seterusnya"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Main"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Buka <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Mainkan <xliff:g id="SONG_NAME">%1$s</xliff:g> oleh <xliff:g id="ARTIST_NAME">%2$s</xliff:g> daripada <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Mainkan <xliff:g id="SONG_NAME">%1$s</xliff:g> daripada <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"Buat asal"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Alihkan lebih dekat untuk bermain pada<xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"Dimainkan pada <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Tidak aktif, semak apl"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Tidak ditemukan"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Kawalan tidak tersedia"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 peranti dipilih"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> peranti dipilih"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(diputuskan sambungan)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Tidak boleh menyambung. Cuba lagi."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Tidak dapat menukar. Ketik untuk mencuba lagi."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Gandingkan peranti baharu"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Nombor binaan"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Nombor binaan disalin ke papan keratan."</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"Lihat semua"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Untuk menukar rangkaian, putuskan sambungan ethernet"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Untuk meningkatkan pengalaman peranti, apl dan perkhidmatan masih dapat melakukan imbasan untuk mengesan rangkaian Wi-Fi pada bila-bila masa, meskipun apabila Wi-Fi dimatikan. Anda boleh menukar tetapan ini dalam tetapan pengimbasan Wi-Fi. "<annotation id="link">"Tukar"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Matikan mod pesawat"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Pilih pengguna"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Apl berjalan di latar"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Berhenti"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ms/tiles_states_strings.xml b/packages/SystemUI/res/values-ms/tiles_states_strings.xml
index b3ee999..60ce1f0 100644
--- a/packages/SystemUI/res/values-ms/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ms/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"Mati"</item>
     <item msgid="460891964396502657">"Hidup"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"Tidak tersedia"</item>
+    <item msgid="5581384648880018330">"Mati"</item>
+    <item msgid="8000850843692192257">"Hidup"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 17fd70e..5ceadae 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"ကိရိယာများ မရှိ"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi-Fi ချိတ်ဆက်ထားခြင်းမရှိပါ"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"အလင်းတောက်ပမှု"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"အရောင်ပြောင်းပြန်"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"အရောင်ပြောင်းပြန်ပြုလုပ်ရန်"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"နောက်ထပ် ဆက်တင်များ"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"အသုံးပြုသူ ဆက်တင်များ"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"ပြီးပါပြီ"</string>
@@ -529,7 +529,7 @@
     <string name="notification_menu_gear_description" msgid="6429668976593634862">"အကြောင်းကြားချက် ထိန်းချုပ်မှုများ"</string>
     <string name="notification_menu_snooze_description" msgid="4740133348901973244">"အကြောင်းကြားချက်များကို ဆိုင်းငံ့ရန် ရွေးချယ်စရာများ"</string>
     <string name="notification_menu_snooze_action" msgid="5415729610393475019">"ကျွန်ုပ်ကို သတိပေးပါ"</string>
-    <string name="snooze_undo" msgid="2738844148845992103">"တစ်ဆင့်နောက်ပြန်ရန်"</string>
+    <string name="snooze_undo" msgid="2738844148845992103">"နောက်ပြန်ရန်"</string>
     <string name="snoozed_for_time" msgid="7586689374860469469">"<xliff:g id="TIME_AMOUNT">%1$s</xliff:g> ဆိုင်းငံ့ရန်"</string>
     <plurals name="snoozeHourOptions" formatted="false" msgid="2066838694120718170">
       <item quantity="other">%d နာရီ</item>
@@ -747,7 +747,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="5217151214439341902">"အများသုံးစွဲနိုင်မှုဆိုင်ရာ ဝန်ဆောင်မှုများ ဖွင့်ရန် တို့ပါ။ ဆက်တင်များတွင် ဤခလုတ်ကို စိတ်ကြိုက်ပြင်ပါ (သို့) လဲပါ။\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>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"ညာဘက်ထိပ်သို့ ရွှေ့ရန်"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"ဆက်တင်များ"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> ၏ <xliff:g id="SONG_NAME">%1$s</xliff:g> ကို <xliff:g id="APP_LABEL">%3$s</xliff:g> တွင် ဖွင့်ထားသည်"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="TOTAL_TIME">%2$s</xliff:g> အနက် <xliff:g id="ELAPSED_TIME">%1$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"ဖွင့်ရန်"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"ခဏရပ်ရန်"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"ယခင် တစ်ပုဒ်"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"နောက်တစ်ပုဒ်"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"ဖွင့်ခြင်း"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> ကို ဖွင့်ပါ"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> ၏ <xliff:g id="SONG_NAME">%1$s</xliff:g> ကို <xliff:g id="APP_LABEL">%3$s</xliff:g> တွင် ဖွင့်ပါ"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="SONG_NAME">%1$s</xliff:g> ကို <xliff:g id="APP_LABEL">%2$s</xliff:g> တွင် ဖွင့်ပါ"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"နောက်ပြန်ရန်"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"<xliff:g id="DEVICENAME">%1$s</xliff:g> တွင်ဖွင့်ရန် အနီးသို့ရွှေ့ပါ"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"<xliff:g id="DEVICENAME">%1$s</xliff:g> တွင်ဖွင့်ထားသည်"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"ရပ်နေသည်၊ အက်ပ်ကို စစ်ဆေးပါ"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"မတွေ့ပါ"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"ထိန်းချုပ်မှု မရနိုင်ပါ"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"စက်ပစ္စည်း ၁ ခုကို ရွေးချယ်ထားသည်"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"စက်ပစ္စည်း <xliff:g id="COUNT">%1$d</xliff:g> ခုကို ရွေးချယ်ထားသည်"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(ချိတ်ဆက်မှု မရှိပါ)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"ချိတ်ဆက်၍ မရပါ။ ထပ်စမ်းကြည့်ပါ။"</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"ပြောင်း၍ မရပါ။ ပြန်စမ်းကြည့်ရန် တို့ပါ။"</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"စက်အသစ် တွဲချိတ်ရန်"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"တည်ဆောက်မှုနံပါတ်"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"တည်ဆောက်မှုနံပါတ်ကို ကလစ်ဘုတ်သို့ မိတ္တူကူးပြီးပါပြီ။"</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"အားလုံးကြည့်ရန်"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ကွန်ရက်ပြောင်းရန် အီသာနက်ကို ချိတ်ဆက်မှုဖြုတ်ပါ"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"စက်ပစ္စည်းကို ပိုမိုကောင်းမွန်စွာ အသုံးပြုနိုင်ရန် Wi-Fi ပိတ်ထားသည့်တိုင် အက်ပ်နှင့် ဝန်ဆောင်မှုများက Wi-Fi ကွန်ရက်များကို အချိန်မရွေး စကင်ဖတ်နိုင်သည်။ ၎င်းကို Wi-Fi ရှာဖွေခြင်း ဆက်တင်များတွင် ပြောင်းနိုင်သည်။ "<annotation id="link">"ပြောင်းရန်"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"လေယာဉ်ပျံမုဒ်ကို ပိတ်ရန်"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"အသုံးပြုသူ ရွေးခြင်း"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"နောက်ခံတွင် ဖွင့်ထားသောအက်ပ်များ"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"ရပ်ရန်"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-my/tiles_states_strings.xml b/packages/SystemUI/res/values-my/tiles_states_strings.xml
index 6c58ac3..7d2f20b 100644
--- a/packages/SystemUI/res/values-my/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-my/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"ပိတ်"</item>
     <item msgid="460891964396502657">"ဖွင့်"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"မရနိုင်ပါ"</item>
+    <item msgid="5581384648880018330">"ပိတ်"</item>
+    <item msgid="8000850843692192257">"ဖွင့်"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 50a1bdb..5aa4dd2 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Ingen enheter er tilgjengelige"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi-Fi er ikke tilkoblet"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Lysstyrke"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Inverter farger"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Fargeinvertering"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"Flere innstillinger"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Brukerinnstillinger"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"Ferdig"</string>
@@ -747,7 +747,7 @@
     <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Forstørr hele skjermen"</string>
     <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Forstørr en del av skjermen"</string>
     <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Bytt"</string>
-    <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Tilgjengelighet-knappen har erstattet tilgjengelighetsbevegelsen\n\n"<annotation id="link">"Se innstillingene"</annotation></string>
+    <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Trykk for å åpne tilgj.funksjoner. Tilpass eller bytt knappen i Innstillinger.\n\n"<annotation id="link">"Se innstillingene"</annotation></string>
     <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Flytt knappen til kanten for å skjule den midlertidig"</string>
     <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Flytt til øverst til venstre"</string>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Flytt til øverst til høyre"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Innstillinger"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> av <xliff:g id="ARTIST_NAME">%2$s</xliff:g> spilles av fra <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> av <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"Spill av"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"Pause"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"Forrige spor"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"Neste spor"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Spill av"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Åpne <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Spill av <xliff:g id="SONG_NAME">%1$s</xliff:g> av <xliff:g id="ARTIST_NAME">%2$s</xliff:g> fra <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Spill av <xliff:g id="SONG_NAME">%1$s</xliff:g> fra <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"Angre"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Flytt nærmere for å spille av på <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"Spilles av på <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Inaktiv. Sjekk appen"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Ikke funnet"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrollen er utilgjengelig"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 enhet er valgt"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> enheter er valgt"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(frakoblet)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Kunne ikke koble til. Prøv på nytt."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Kan ikke bytte. Trykk for å prøve igjen."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Koble til en ny enhet"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Delversjonsnummer"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Delversjonsnummeret er kopiert til utklippstavlen."</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"Se alle"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"For å bytte nettverk, koble fra Ethernet"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"For å forbedre brukeropplevelsen på enheten kan apper og tjenester søke etter Wi-Fi-nettverk når som helst – også når Wi-Fi er slått av. Du kan endre dette i innstillingene for Wi-Fi-skanning. "<annotation id="link">"Bytt"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Slå av flymodus"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Velg bruker"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Apper som kjører i bakgrunnen"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Stopp"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-nb/tiles_states_strings.xml b/packages/SystemUI/res/values-nb/tiles_states_strings.xml
index a40e4a4..e512a84 100644
--- a/packages/SystemUI/res/values-nb/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-nb/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"Av"</item>
     <item msgid="460891964396502657">"På"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"Utilgjengelig"</item>
+    <item msgid="5581384648880018330">"Av"</item>
+    <item msgid="8000850843692192257">"På"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 64881eb..afa8f1f 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"कुनै उपकरणहरू उपलब्ध छैन"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi-Fi जडान गरिएको छैन"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"उज्यालपन"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"रंग उल्टाउनुहोस्"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"कलर इन्भर्सन"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"थप सेटिङहरू"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"प्रयोगकर्तासम्बन्धी सेटिङ"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"भयो"</string>
@@ -747,7 +747,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="5217151214439341902">"सर्वसुलभता कायम गर्ने सुविधा खोल्न ट्याप गर्नुहोस्। सेटिङमा गई यो बटन कस्टमाइज गर्नुहोस् वा बदल्नुहोस्।\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>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"सिरानको दायाँतिर सार्नुहोस्"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"सेटिङ"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> को <xliff:g id="SONG_NAME">%1$s</xliff:g> बोलको गीत <xliff:g id="APP_LABEL">%3$s</xliff:g> मा बज्दै छ"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="TOTAL_TIME">%2$s</xliff:g> मध्ये <xliff:g id="ELAPSED_TIME">%1$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"प्ले गर्नुहोस्"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"पज गर्नुहोस्"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"अघिल्लो ट्रयाक"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"अर्को ट्र्याक"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"प्ले गर्नुहोस्"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> खोल्नुहोस्"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> को <xliff:g id="SONG_NAME">%1$s</xliff:g> बोलको गीत <xliff:g id="APP_LABEL">%3$s</xliff:g> मा बजाउनुहोस्"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="SONG_NAME">%1$s</xliff:g> बोलको गीत <xliff:g id="APP_LABEL">%2$s</xliff:g> मा बजाउनुहोस्"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"अन्डू गर्नुहोस्"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"<xliff:g id="DEVICENAME">%1$s</xliff:g> मा प्ले गर्न आफ्नो डिभाइस नजिकै लैजानुहोस्"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"<xliff:g id="DEVICENAME">%1$s</xliff:g> मा प्ले गरिँदै छ"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"निष्क्रिय छ, एप जाँच गर्नु…"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"फेला परेन"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"नियन्त्रण उपलब्ध छैन"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"१ यन्त्र चयन गरियो"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> वटा यन्त्र चयन गरिए"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(डिस्कनेक्ट गरिएको छ)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"कनेक्ट गर्न सकिएन। फेरि प्रयास गर्नुहोस्।"</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"बदल्न सकिएन। फेरि प्रयास गर्न ट्याप गर्नुहोस्।"</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"नयाँ डिभाइस कनेक्ट गर्नुहोस्"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"बिल्ड नम्बर"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"बिल्ड नम्बर कपी गरी क्लिपबोर्डमा सारियो।"</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"सबै नेटवर्क हेर्नुहोस्"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"नेटवर्क बदल्न इथरनेट डिस्कनेक्ट गर्नुहोस्"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"डिभाइस प्रयोगको अनुभवमा गुणस्तर सुधार गर्न, एप तथा सेवाहरूले अझै पनि जुनसुकै बेला (Wi‑Fi अफ भएका बेलामा पनि) Wi‑Fi नेटवर्क खोज्न सक्छन्। तपाईं यसलाई Wi‑Fi स्क्यानिङका सेटिङमा गई परिवर्तन गर्न सक्नुहुन्छ। "<annotation id="link">"बदल्नुहोस्"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"हवाइजहाज मोड अफ गर्नुहोस्"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"प्रयोगकर्ता चयन गर्नु…"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"अहिले ब्याकग्राउन्डमा चलिरहेका एप"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"रोक्नुहोस्"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ne/tiles_states_strings.xml b/packages/SystemUI/res/values-ne/tiles_states_strings.xml
index 373044d..355df40 100644
--- a/packages/SystemUI/res/values-ne/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ne/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"अफ छ"</item>
     <item msgid="460891964396502657">"अन छ"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"उपलब्ध छैन"</item>
+    <item msgid="5581384648880018330">"अफ छ"</item>
+    <item msgid="8000850843692192257">"अन छ"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 093ba95..09b278f 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Geen apparaten beschikbaar"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wifi niet verbonden"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Helderheid"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Kleuren omkeren"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Kleurinversie"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"Meer instellingen"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Gebruikersinstellingen"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"Klaar"</string>
@@ -747,7 +747,7 @@
     <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Volledig scherm vergroten"</string>
     <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Deel van het scherm vergroten"</string>
     <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Schakelen"</string>
-    <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"De knop Toegankelijkheid vervangt het toegankelijkheidsgebaar\n\n"<annotation id="link">"Instellingen bekijken"</annotation></string>
+    <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Tik voor toegankelijkheidsfuncties. Wijzig of vervang deze knop via Instellingen.\n\n"<annotation id="link">"Naar Instellingen"</annotation></string>
     <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Knop naar de rand verplaatsen om deze tijdelijk te verbergen"</string>
     <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Naar linksboven verplaatsen"</string>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Naar rechtsboven verplaatsen"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Instellingen"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> van <xliff:g id="ARTIST_NAME">%2$s</xliff:g> wordt afgespeeld via <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> van <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"Afspelen"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"Pauzeren"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"Vorige track"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"Volgende track"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Afspelen"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> openen"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="SONG_NAME">%1$s</xliff:g> van <xliff:g id="ARTIST_NAME">%2$s</xliff:g> afspelen via <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="SONG_NAME">%1$s</xliff:g> afspelen via <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"Ongedaan maken"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Ga dichter naar <xliff:g id="DEVICENAME">%1$s</xliff:g> toe om af te spelen"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"Afspelen op <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Inactief, check de app"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Niet gevonden"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Beheeroptie niet beschikbaar"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"Eén apparaat geselecteerd"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> apparaten geselecteerd"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(verbinding verbroken)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Kan geen verbinding maken. Probeer het nog eens."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Kan niet schakelen. Tik om het opnieuw te proberen."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Nieuw apparaat koppelen"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Build-nummer"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Build-nummer naar klembord gekopieerd."</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"Alles tonen"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Verbreek de ethernetverbinding om van netwerk te wisselen"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Apps en services kunnen nog steeds op elk moment scannen op wifi-netwerken, zelfs als wifi uitstaat, om de apparaatfunctionaliteit te verbeteren. Je kunt dit aanpassen in de instellingen voor wifi-scannen. "<annotation id="link">"Wijzigen"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Vliegtuigmodus uitzetten"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Gebruiker selecteren"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Apps die op de achtergrond worden uitgevoerd"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Stoppen"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-nl/tiles_states_strings.xml b/packages/SystemUI/res/values-nl/tiles_states_strings.xml
index 6d2ef5f..fa85b88 100644
--- a/packages/SystemUI/res/values-nl/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-nl/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"Uit"</item>
     <item msgid="460891964396502657">"Aan"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"Niet beschikbaar"</item>
+    <item msgid="5581384648880018330">"Uit"</item>
+    <item msgid="8000850843692192257">"Aan"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 931d696..0d0cea5 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"କୌଣସି ଡିଭାଇସ୍ ଉପଲବ୍ଧ ନାହିଁ"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"ୱାଇ-ଫାଇ ସଂଯୋଜିତ ହୋଇନାହିଁ"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"ଉଜ୍ଜ୍ୱଳତା"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"ରଙ୍ଗ ଇନଭାର୍ଟ୍ କରନ୍ତୁ"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"ରଙ୍ଗ ଇନଭାର୍ସନ"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"ଅଧିକ ସେଟିଂସ୍"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"ଉପଯୋଗକର୍ତ୍ତା ସେଟିଂସ୍"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"ହୋଇଗଲା"</string>
@@ -747,7 +747,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="5217151214439341902">"ଆକ୍ସେସିବିଲିଟୀ ଫିଚର ଖୋଲିବାକୁ ଟାପ କରନ୍ତୁ। ସେଟିଂସରେ ଏହି ବଟନକୁ କଷ୍ଟମାଇଜ କର କିମ୍ବା ବଦଳାଅ।\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>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"ଶୀର୍ଷ ଡାହାଣକୁ ମୁଭ୍ କରନ୍ତୁ"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"ସେଟିଂସ୍"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g>ରୁ <xliff:g id="ARTIST_NAME">%2$s</xliff:g>ଙ୍କ <xliff:g id="SONG_NAME">%1$s</xliff:g> ଚାଲୁଛି"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="TOTAL_TIME">%2$s</xliff:g>ରୁ <xliff:g id="ELAPSED_TIME">%1$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"ଚଲାନ୍ତୁ"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"ବିରତ କରନ୍ତୁ"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"ପୂର୍ବବର୍ତ୍ତୀ ଟ୍ରାକ"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"ପରବର୍ତ୍ତୀ ଟ୍ରାକ"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"ଚଲାନ୍ତୁ"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> ଖୋଲନ୍ତୁ"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="APP_LABEL">%3$s</xliff:g>ରୁ <xliff:g id="ARTIST_NAME">%2$s</xliff:g>ଙ୍କ <xliff:g id="SONG_NAME">%1$s</xliff:g> ଚଲାନ୍ତୁ"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="APP_LABEL">%2$s</xliff:g>ରୁ <xliff:g id="SONG_NAME">%1$s</xliff:g> ଚଲାନ୍ତୁ"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"ପୂର୍ବବତ୍ କରନ୍ତୁ"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"<xliff:g id="DEVICENAME">%1$s</xliff:g>ରେ ଚଲାଇବା ପାଇଁ ନିକଟକୁ ଯାଆନ୍ତୁ"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"<xliff:g id="DEVICENAME">%1$s</xliff:g>ରେ ଚାଲୁଛି"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"ନିଷ୍କ୍ରିୟ ଅଛି, ଆପ ଯାଞ୍ଚ କରନ୍ତୁ"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"ମିଳିଲା ନାହିଁ"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"ନିୟନ୍ତ୍ରଣ ଉପଲବ୍ଧ ନାହିଁ"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1ଟି ଡିଭାଇସ୍ ଚୟନ କରାଯାଇଛି"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g>ଟି ଡିଭାଇସ୍ ଚୟନ କରାଯାଇଛି"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(ବିଚ୍ଛିନ୍ନ କରାଯାଇଛି)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"ସଂଯୋଗ କରାଯାଇପାରିଲା ନାହିଁ। ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"ସ୍ୱିଚ କରାଯାଇପାରିବ ନାହିଁ। ପୁଣି ଚେଷ୍ଟା କରିବାକୁ ଟାପ କରନ୍ତୁ।"</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"ନୂଆ ଡିଭାଇସକୁ ପେୟାର୍ କରନ୍ତୁ"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"ବିଲ୍ଡ ନମ୍ୱର"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"କ୍ଲିପବୋର୍ଡକୁ କପି କରାଯାଇଥିବା ବିଲ୍ଡ ନମ୍ୱର।"</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"ସବୁ ଦେଖନ୍ତୁ"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ନେଟୱାର୍କ ସ୍ୱିଚ୍ କରିବାକୁ, ଇଥରନେଟ୍ ବିଚ୍ଛିନ୍ନ କରନ୍ତୁ"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"ଡିଭାଇସ ଅନୁଭୂତିକୁ ଉନ୍ନତ କରିବା ପାଇଁ, ୱାଇ-ଫାଇ ବନ୍ଦ ଥିଲେ ମଧ୍ୟ ଆପ ଓ ସେବାଗୁଡ଼ିକ ଏବେ ବି ଯେ କୌଣସି ସମୟରେ ୱାଇ-ଫାଇ ନେଟୱାର୍କ ପାଇଁ ସ୍କାନ କରିପାରିବ। ଆପଣ ଏହାକୁ ୱାଇ-ଫାଇ ସ୍କାନିଂ ସେଟିଂସରେ ପରିବର୍ତ୍ତନ କରିପାରିବେ। "<annotation id="link">"ପରିବର୍ତ୍ତନ କରନ୍ତୁ"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"ଏୟାରପ୍ଲେନ ମୋଡ ବନ୍ଦ କରନ୍ତୁ"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"ଉପଯୋଗକର୍ତ୍ତା ଚୟନ କର"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"ପୃଷ୍ଠପଟରେ ଚାଲୁଥିବା ଆପଗୁଡ଼ିକ"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"ବନ୍ଦ କରନ୍ତୁ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-or/tiles_states_strings.xml b/packages/SystemUI/res/values-or/tiles_states_strings.xml
index 6b52d6e..bb94e0d 100644
--- a/packages/SystemUI/res/values-or/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-or/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"ବନ୍ଦ ଅଛି"</item>
     <item msgid="460891964396502657">"ଚାଲୁ ଅଛି"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"ଉପଲବ୍ଧ ନାହିଁ"</item>
+    <item msgid="5581384648880018330">"ବନ୍ଦ ଅଛି"</item>
+    <item msgid="8000850843692192257">"ଚାଲୁ ଅଛି"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index d2b2cb5..902f36c 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"ਕੋਈ ਡਿਵਾਈਸਾਂ ਉਪਲਬਧ ਨਹੀਂ"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"ਵਾਈ-ਫਾਈ ਕਨੈਕਟ ਨਹੀਂ ਕੀਤਾ ਗਿਆ"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"ਚਮਕ"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"ਰੰਗ ਪਲਟਾਓ"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"ਰੰਗ ਪਲਟਨਾ"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"ਹੋਰ ਸੈਟਿੰਗਾਂ"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"ਵਰਤੋਂਕਾਰ ਸੈਟਿੰਗਾਂ"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"ਹੋ ਗਿਆ"</string>
@@ -747,7 +747,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="5217151214439341902">"ਪਹੁੰਚਯੋਗਤਾ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਖੋਲ੍ਹਣ ਲਈ ਟੈਪ ਕਰੋ। ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਇਹ ਬਟਨ ਵਿਉਂਤਬੱਧ ਕਰੋ ਜਾਂ ਬਦਲੋ।\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>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"ਉੱਪਰ ਵੱਲ ਸੱਜੇ ਲਿਜਾਓ"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"ਸੈਟਿੰਗਾਂ"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g> ਤੋਂ <xliff:g id="ARTIST_NAME">%2$s</xliff:g> ਦਾ <xliff:g id="SONG_NAME">%1$s</xliff:g> ਚੱਲ ਰਿਹਾ ਹੈ"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="TOTAL_TIME">%2$s</xliff:g> ਵਿੱਚੋਂ <xliff:g id="ELAPSED_TIME">%1$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"ਚਲਾਓ"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"ਰੋਕੋ"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"ਪਿਛਲਾ ਟਰੈਕ"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"ਅਗਲਾ ਟਰੈਕ"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"ਚਲਾਓ"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> ਖੋਲ੍ਹੋ"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="APP_LABEL">%3$s</xliff:g> ਤੋਂ <xliff:g id="ARTIST_NAME">%2$s</xliff:g> ਦਾ <xliff:g id="SONG_NAME">%1$s</xliff:g> ਚਲਾਓ"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="APP_LABEL">%2$s</xliff:g> ਤੋਂ <xliff:g id="SONG_NAME">%1$s</xliff:g> ਚਲਾਓ"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"ਅਣਕੀਤਾ ਕਰੋ"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"<xliff:g id="DEVICENAME">%1$s</xliff:g> \'ਤੇ ਚਲਾਉਣ ਲਈ ਨੇੜੇ ਲਿਜਾਓ"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"<xliff:g id="DEVICENAME">%1$s</xliff:g> \'ਤੇ ਚਲਾਇਆ ਜਾ ਰਿਹਾ ਹੈ"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"ਅਕਿਰਿਆਸ਼ੀਲ, ਐਪ ਦੀ ਜਾਂਚ ਕਰੋ"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"ਨਹੀਂ ਮਿਲਿਆ"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"ਕੰਟਰੋਲ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 ਡੀਵਾਈਸ ਨੂੰ ਚੁਣਿਆ ਗਿਆ"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> ਡੀਵਾਈਸਾਂ ਨੂੰ ਚੁਣਿਆ ਗਿਆ"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(ਡਿਸਕਨੈਕਟ ਹੈ)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"ਕਨੈਕਟ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ। ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"ਬਦਲਿਆ ਨਹੀਂ ਜਾ ਸਕਦਾ। ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।"</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"ਨਵਾਂ ਡੀਵਾਈਸ ਜੋੜਾਬੱਧ ਕਰੋ"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"ਬਿਲਡ ਨੰਬਰ"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"ਬਿਲਡ ਨੰਬਰ ਨੂੰ ਕਲਿੱਪਬੋਰਡ \'ਤੇ ਕਾਪੀ ਕੀਤਾ ਗਿਆ।"</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"ਸਭ ਦੇਖੋ"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ਨੈੱਟਵਰਕਾਂ ਨੂੰ ਬਦਲਣ ਲਈ, ਈਥਰਨੈੱਟ ਨੂੰ ਡਿਸਕਨੈਕਟ ਕਰੋ"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"ਡੀਵਾਈਸ ਦੇ ਅਨੁਭਵ ਨੂੰ ਬਿਹਤਰ ਬਣਾਉਣ ਲਈ, ਐਪਾਂ ਅਤੇ ਸੇਵਾਵਾਂ ਕਿਸੇ ਵੀ ਸਮੇਂ ਵਾਈ-ਫਾਈ ਨੈੱਟਵਰਕਾਂ ਲਈ ਸਕੈਨ ਕਰ ਸਕਦੀਆਂ ਹਨ, ਭਾਵੇਂ ਵਾਈ-ਫਾਈ ਬੰਦ ਹੀ ਕਿਉਂ ਨਾ ਹੋਵੇ। ਤੁਸੀਂ ਇਸ ਨੂੰ ਵਾਈ‑ਫਾਈ ਸਕੈਨਿੰਗ ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਜਾ ਕੇ ਬਦਲ ਸਕਦੇ ਹੋ। "<annotation id="link">"ਬਦਲੋ"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"ਹਵਾਈ-ਜਹਾਜ਼ ਮੋਡ ਬੰਦ ਕਰੋ"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"ਵਰਤੋਂਕਾਰ ਚੁਣੋ"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"ਬੈਕਗ੍ਰਾਊਂਡ ਵਿੱਚ ਚੱਲ ਰਹੀਆਂ ਐਪਾਂ"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"ਬੰਦ ਕਰੋ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pa/tiles_states_strings.xml b/packages/SystemUI/res/values-pa/tiles_states_strings.xml
index d44add8..2403141c 100644
--- a/packages/SystemUI/res/values-pa/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-pa/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"ਬੰਦ"</item>
     <item msgid="460891964396502657">"ਚਾਲੂ"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"ਅਣਉਪਲਬਧ"</item>
+    <item msgid="5581384648880018330">"ਬੰਦ"</item>
+    <item msgid="8000850843692192257">"ਚਾਲੂ"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 0e8b97e..3d09c50 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -252,7 +252,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Brak dostępnych urządzeń"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Brak połączenia z Wi-Fi"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Jasność"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Odwróć kolory"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Odwrócenie kolorów"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"Więcej ustawień"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Ustawienia użytkownika"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"Gotowe"</string>
@@ -757,7 +757,7 @@
     <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Powiększanie pełnego ekranu"</string>
     <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Powiększ część ekranu"</string>
     <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Przełącz"</string>
-    <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Przycisk ułatwień dostępu zastąpił gest ułatwień dostępu\n\n"<annotation id="link">"Wyświetl ustawienia"</annotation></string>
+    <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Kliknij, aby otworzyć ułatwienia dostępu. Dostosuj lub zmień ten przycisk w Ustawieniach.\n\n"<annotation id="link">"Wyświetl ustawienia"</annotation></string>
     <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Przesuń przycisk do krawędzi, aby ukryć go tymczasowo"</string>
     <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Przenieś w lewy górny róg"</string>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Przenieś w prawy górny róg"</string>
@@ -810,10 +810,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Ustawienia"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"Aplikacja <xliff:g id="APP_LABEL">%3$s</xliff:g> odtwarza utwór <xliff:g id="SONG_NAME">%1$s</xliff:g> (<xliff:g id="ARTIST_NAME">%2$s</xliff:g>)"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> z <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"Odtwórz"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"Wstrzymaj"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"Poprzedni utwór"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"Następny utwór"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Odtwórz"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Otwórz aplikację <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Odtwórz utwór <xliff:g id="SONG_NAME">%1$s</xliff:g> (<xliff:g id="ARTIST_NAME">%2$s</xliff:g>) w aplikacji <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Odtwórz utwór <xliff:g id="SONG_NAME">%1$s</xliff:g> w aplikacji <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"Cofnij"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Przysuń się bliżej, aby odtwarzać na urządzeniu <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"Odtwarzam na urządzeniu <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Nieaktywny, sprawdź aplikację"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Nie znaleziono"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Element jest niedostępny"</string>
@@ -828,7 +835,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"Wybrano 1 urządzenie"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"Wybrane urządzenia: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(odłączono)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Nie udało się połączyć. Spróbuj ponownie."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Nie można przełączyć. Spróbuj ponownie."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Sparuj nowe urządzenie"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Numer kompilacji"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Numer kompilacji został skopiowany do schowka."</string>
@@ -893,8 +900,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"Pokaż wszystko"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Aby przełączać sieci, odłącz Ethernet"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Aby zapewnić Ci większy komfort korzystania z urządzenia, aplikacje i usługi mogą nadal wyszukiwać sieci Wi-Fi w pobliżu nawet wtedy, gdy Wi-Fi jest wyłączone. Możesz to zmienić w ustawieniach skanowania Wi-Fi. "<annotation id="link">"Zmień"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Wyłącz tryb samolotowy"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Wybierz użytkownika"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Aplikacje działające w tle"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Zatrzymaj"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pl/tiles_states_strings.xml b/packages/SystemUI/res/values-pl/tiles_states_strings.xml
index 4d7ed15..30026e8 100644
--- a/packages/SystemUI/res/values-pl/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-pl/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"Wyłączony"</item>
     <item msgid="460891964396502657">"Włączony"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"Brak dostępu"</item>
+    <item msgid="5581384648880018330">"Wyłączono"</item>
+    <item msgid="8000850843692192257">"Włączono"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 90cac8a..e166fa4 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Não há dispositivos disponíveis"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi-Fi não conectado"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Brilho"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Inverter cores"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inversão de cores"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"Mais configurações"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Config. do usuário"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"Concluído"</string>
@@ -747,7 +747,7 @@
     <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Ampliar toda a tela"</string>
     <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Ampliar parte da tela"</string>
     <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Trocar"</string>
-    <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"O botão de acessibilidade substituiu o gesto de acessibilidade\n\n"<annotation id="link">"Veja as configurações"</annotation></string>
+    <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Toque para abrir os recursos de acessibilidade. Personalize ou substitua o botão nas Configurações.\n\n"<annotation id="link">"Ver configurações"</annotation></string>
     <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Mova o botão para a borda para ocultá-lo temporariamente"</string>
     <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Mover para o canto superior esquerdo"</string>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Mover para o canto superior direito"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Configurações"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"Tocando <xliff:g id="SONG_NAME">%1$s</xliff:g> de <xliff:g id="ARTIST_NAME">%2$s</xliff:g> no app <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> de <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"Iniciar"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"Pausar"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"Faixa anterior"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"Próxima faixa"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Iniciar"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Abrir <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Tocar <xliff:g id="SONG_NAME">%1$s</xliff:g> de <xliff:g id="ARTIST_NAME">%2$s</xliff:g> no app <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Tocar <xliff:g id="SONG_NAME">%1$s</xliff:g> no app <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"Desfazer"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Aproxime os dispositivos para ouvir música no <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"Reproduzido em <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Inativo, verifique o app"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Não encontrado"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"O controle está indisponível"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 dispositivo selecionado"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> dispositivos selecionados"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(sem conexão)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Não foi possível conectar. Tente novamente."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Não foi possível mudar. Toque para tentar novamente."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Parear novo dispositivo"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Número da versão"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Número da versão copiado para a área de transferência."</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"Ver tudo"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Para mudar de rede, desconecte o cabo Ethernet"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Para melhorar a experiência no dispositivo, os apps e serviços ainda podem procurar redes Wi-Fi a qualquer momento, mesmo quando o Wi-Fi estiver desativado. Você pode mudar essa opção nas configurações de busca por Wi-Fi. "<annotation id="link">"Mudar"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Desativar modo avião"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Selecionar usuário"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Apps em execução em segundo plano"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Parar"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/tiles_states_strings.xml b/packages/SystemUI/res/values-pt-rBR/tiles_states_strings.xml
index ca1ef44..f874dd4 100644
--- a/packages/SystemUI/res/values-pt-rBR/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"Desativado"</item>
     <item msgid="460891964396502657">"Ativado"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"Indisponível"</item>
+    <item msgid="5581384648880018330">"Desativado"</item>
+    <item msgid="8000850843692192257">"Ativado"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index e2d8433..808dd2b 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Sem dispositivos disponíveis"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi-Fi não ligado"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Brilho"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Inverter cores"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inversão de cores"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"Mais definições"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Definições do utilizador"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"Concluído"</string>
@@ -747,7 +747,7 @@
     <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Ampliar o ecrã inteiro"</string>
     <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Ampliar parte do ecrã"</string>
     <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Mudar"</string>
-    <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"O botão Acessibilidade substituiu o gesto de acessibilidade\n\n"<annotation id="link">"Ver definições"</annotation></string>
+    <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Toque para abrir funcionalidades de acessibilidade. Personal. ou substitua botão em Defin.\n\n"<annotation id="link">"Ver defin."</annotation></string>
     <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Mova o botão para a extremidade para o ocultar temporariamente"</string>
     <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Mover p/ parte sup. esquerda"</string>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Mover parte superior direita"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Definições"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> de <xliff:g id="ARTIST_NAME">%2$s</xliff:g> em reprodução a partir da app <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> de <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"Reproduzir"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"Pausar"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"Faixa anterior"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"Faixa seguinte"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Reproduzir"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Abrir <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Reproduzir <xliff:g id="SONG_NAME">%1$s</xliff:g> de <xliff:g id="ARTIST_NAME">%2$s</xliff:g> a partir da app <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Reproduzir <xliff:g id="SONG_NAME">%1$s</xliff:g> a partir da app <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"Anular"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Aproxime-se para reproduzir no dispositivo <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"A reproduzir no dispositivo <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Inativa. Consulte a app."</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Não encontrado."</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"O controlo está indisponível"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 dispositivo selecionado"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> dispositivos selecionados"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(desligado)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Não foi possível ligar. Tente novamente."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Não é possível mudar. Toque para tentar novamente."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Sincronize o novo dispositivo"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Número da compilação"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Número da compilação copiado para a área de transferência."</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"Veja tudo"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Para mudar de rede, desligue a Ethernet"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Para melhorar a experiência do dispositivo, as apps e os serviços podem continuar a procurar redes Wi-Fi em qualquer altura, mesmo quando o Wi-Fi está desativado. Pode alterar esta opção nas definições de procura de Wi-Fi. "<annotation id="link">"Alterar"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Desative o modo de avião"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Selecione utilizador"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Apps em execução em segundo plano"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Parar"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/tiles_states_strings.xml b/packages/SystemUI/res/values-pt-rPT/tiles_states_strings.xml
index 632db66..1e426e1 100644
--- a/packages/SystemUI/res/values-pt-rPT/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"Desativado"</item>
     <item msgid="460891964396502657">"Ativado"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"Indisponível"</item>
+    <item msgid="5581384648880018330">"Desligado"</item>
+    <item msgid="8000850843692192257">"Ligado"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 90cac8a..e166fa4 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Não há dispositivos disponíveis"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi-Fi não conectado"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Brilho"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Inverter cores"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inversão de cores"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"Mais configurações"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Config. do usuário"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"Concluído"</string>
@@ -747,7 +747,7 @@
     <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Ampliar toda a tela"</string>
     <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Ampliar parte da tela"</string>
     <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Trocar"</string>
-    <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"O botão de acessibilidade substituiu o gesto de acessibilidade\n\n"<annotation id="link">"Veja as configurações"</annotation></string>
+    <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Toque para abrir os recursos de acessibilidade. Personalize ou substitua o botão nas Configurações.\n\n"<annotation id="link">"Ver configurações"</annotation></string>
     <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Mova o botão para a borda para ocultá-lo temporariamente"</string>
     <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Mover para o canto superior esquerdo"</string>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Mover para o canto superior direito"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Configurações"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"Tocando <xliff:g id="SONG_NAME">%1$s</xliff:g> de <xliff:g id="ARTIST_NAME">%2$s</xliff:g> no app <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> de <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"Iniciar"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"Pausar"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"Faixa anterior"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"Próxima faixa"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Iniciar"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Abrir <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Tocar <xliff:g id="SONG_NAME">%1$s</xliff:g> de <xliff:g id="ARTIST_NAME">%2$s</xliff:g> no app <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Tocar <xliff:g id="SONG_NAME">%1$s</xliff:g> no app <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"Desfazer"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Aproxime os dispositivos para ouvir música no <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"Reproduzido em <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Inativo, verifique o app"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Não encontrado"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"O controle está indisponível"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 dispositivo selecionado"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> dispositivos selecionados"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(sem conexão)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Não foi possível conectar. Tente novamente."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Não foi possível mudar. Toque para tentar novamente."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Parear novo dispositivo"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Número da versão"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Número da versão copiado para a área de transferência."</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"Ver tudo"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Para mudar de rede, desconecte o cabo Ethernet"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Para melhorar a experiência no dispositivo, os apps e serviços ainda podem procurar redes Wi-Fi a qualquer momento, mesmo quando o Wi-Fi estiver desativado. Você pode mudar essa opção nas configurações de busca por Wi-Fi. "<annotation id="link">"Mudar"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Desativar modo avião"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Selecionar usuário"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Apps em execução em segundo plano"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Parar"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pt/tiles_states_strings.xml b/packages/SystemUI/res/values-pt/tiles_states_strings.xml
index ca1ef44..f874dd4 100644
--- a/packages/SystemUI/res/values-pt/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-pt/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"Desativado"</item>
     <item msgid="460891964396502657">"Ativado"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"Indisponível"</item>
+    <item msgid="5581384648880018330">"Desativado"</item>
+    <item msgid="8000850843692192257">"Ativado"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 5c89fb1..0fdd176 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -251,7 +251,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Niciun dispozitiv disponibil"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Rețeaua Wi-Fi nu este conectată"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Luminozitate"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Inversați culorile"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inversarea culorilor"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"Mai multe setări"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Setări de utilizator"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"Terminat"</string>
@@ -752,7 +752,7 @@
     <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Măriți tot ecranul"</string>
     <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Măriți o parte a ecranului"</string>
     <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Comutator"</string>
-    <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Butonul de accesibilitate a înlocuit gestul de accesibilitate\n\n"<annotation id="link">"Vedeți setările"</annotation></string>
+    <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Atingeți pentru a deschide funcțiile de accesibilitate. Personalizați sau înlocuiți butonul în Setări.\n\n"<annotation id="link">"Afișați setările"</annotation></string>
     <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Mutați butonul spre margine pentru a-l ascunde temporar"</string>
     <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Mutați în stânga sus"</string>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Mutați în dreapta sus"</string>
@@ -804,10 +804,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Setări"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> de la <xliff:g id="ARTIST_NAME">%2$s</xliff:g> se redă în <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> din <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"Redați"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"Întrerupeți"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"Melodia anterioară"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"Melodia următoare"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Redați"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Deschideți <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Redați <xliff:g id="SONG_NAME">%1$s</xliff:g> de la <xliff:g id="ARTIST_NAME">%2$s</xliff:g> în <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Redați <xliff:g id="SONG_NAME">%1$s</xliff:g> în <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"Anulați"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Apropiați-vă pentru a reda pe <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"Se redă pe <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Inactiv, verificați aplicația"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Nu s-a găsit"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Comanda este indisponibilă"</string>
@@ -822,7 +829,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"S-a selectat un dispozitiv"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"S-au selectat <xliff:g id="COUNT">%1$d</xliff:g> dispozitive"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(deconectat)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Nu s-a putut conecta. Reîncercați."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Nu se poate comuta. Atingeți pentru a încerca din nou."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Asociați un nou dispozitiv"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Numărul versiunii"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Numărul versiunii s-a copiat în clipboard."</string>
@@ -887,8 +894,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"Afișează-le pe toate"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Pentru a schimba rețeaua, deconectați ethernet"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Pentru a îmbunătăți experiența cu dispozitivul, aplicațiile și serviciile pot să caute în continuare rețele Wi‑Fi chiar și atunci când conexiunea Wi-Fi este dezactivată. Puteți să schimbați acest aspect din setările pentru căutarea de rețele Wi-Fi. "<annotation id="link">"Schimbați"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Dezactivați modul Avion"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Alegeți utilizatorul"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Aplicațiile rulează în fundal"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Opriți"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ro/tiles_states_strings.xml b/packages/SystemUI/res/values-ro/tiles_states_strings.xml
index eea69f8..c63e7fe 100644
--- a/packages/SystemUI/res/values-ro/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ro/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"Dezactivat"</item>
     <item msgid="460891964396502657">"Activat"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"Indisponibil"</item>
+    <item msgid="5581384648880018330">"Dezactivat"</item>
+    <item msgid="8000850843692192257">"Activat"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index ecff557..2b06d10 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -252,7 +252,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Нет доступных устройств"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Нет подключения к сети Wi-Fi."</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Яркость"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Обратные цвета"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Инверсия цветов"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"Настройки"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Пользовательские настройки"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"Готово"</string>
@@ -757,7 +757,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="5217151214439341902">"Нажмите, чтобы открыть спец. возможности. Настройте или замените эту кнопку в настройках.\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>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Перенести в правый верхний угол"</string>
@@ -810,10 +810,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Настройки"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"Воспроизводится медиафайл \"<xliff:g id="SONG_NAME">%1$s</xliff:g>\" (исполнитель: <xliff:g id="ARTIST_NAME">%2$s</xliff:g>) из приложения \"<xliff:g id="APP_LABEL">%3$s</xliff:g>\"."</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> из <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"Воспроизвести"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"Приостановить"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"Предыдущий трек"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"Следующий трек"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Воспроизведение"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Открыть приложение \"<xliff:g id="APP_LABEL">%1$s</xliff:g>\""</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Воспроизвести медиафайл \"<xliff:g id="SONG_NAME">%1$s</xliff:g>\" (исполнитель: <xliff:g id="ARTIST_NAME">%2$s</xliff:g>) из приложения \"<xliff:g id="APP_LABEL">%3$s</xliff:g>\""</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Воспроизвести медиафайл \"<xliff:g id="SONG_NAME">%1$s</xliff:g>\" из приложения \"<xliff:g id="APP_LABEL">%2$s</xliff:g>\""</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"Отменить"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Чтобы включить музыку на устройстве \"<xliff:g id="DEVICENAME">%1$s</xliff:g>\", подойдите к нему ближе."</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"Воспроизводится на устройстве \"<xliff:g id="DEVICENAME">%1$s</xliff:g>\"."</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Нет ответа. Проверьте приложение."</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Не найдено."</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Управление недоступно"</string>
@@ -828,7 +835,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"Выбрано 1 устройство"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"Выбрано устройств: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(нет подключения)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Не удалось подключиться. Повторите попытку."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Не удается переключиться. Нажмите, чтобы повторить попытку."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Подключить новое устройство"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Номер сборки"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Номер сборки скопирован в буфер обмена."</string>
@@ -893,8 +900,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"Показать все"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Чтобы переключиться между сетями, отключите кабель Ethernet."</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Чтобы улучшать работу устройства, приложения и сервисы могут искать беспроводные сети в любое время, даже если вы отключили Wi‑Fi. Чтобы запретить это, отключите поиск сетей Wi‑Fi. "<annotation id="link">"Открыть настройки"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Отключить режим полета"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Выберите профиль"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Приложения, работающие в фоновом режиме"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Остановить"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ru/tiles_states_strings.xml b/packages/SystemUI/res/values-ru/tiles_states_strings.xml
index 6bc486b..ae31f32 100644
--- a/packages/SystemUI/res/values-ru/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ru/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"Отключен"</item>
     <item msgid="460891964396502657">"Включен"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"Недоступно"</item>
+    <item msgid="5581384648880018330">"Отключено"</item>
+    <item msgid="8000850843692192257">"Включено"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index b24db63..bdd41a5 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"උපාංග නොතිබේ"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi-Fi සම්බන්ධ නොවීය"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"දීප්තිමත් බව"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"වර්ණ යටිකුරු කරන්න"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"වර්ණ අපවර්තනය"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"තව සැකසීම්"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"පරිශීලක සැකසීම්"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"නිමයි"</string>
@@ -747,7 +747,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="5217151214439341902">"ප්‍රවේශ්‍යතා විශේෂාංග විවෘත කිරීමට තට්ටු කරන්න. සැකසීම් තුළ මෙම බොත්තම අභිරුචිකරණය හෝ ප්‍රතිස්ථාපනය කරන්න.\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>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"ඉහළ දකුණට ගෙන යන්න"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"සැකසීම්"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g>ගේ <xliff:g id="SONG_NAME">%1$s</xliff:g> ගීතය <xliff:g id="APP_LABEL">%3$s</xliff:g> වෙතින් ධාවනය වෙමින් පවතී"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="TOTAL_TIME">%2$s</xliff:g>කින් <xliff:g id="ELAPSED_TIME">%1$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"වාදනය කරන්න"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"විරාම ගන්වන්න"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"පෙර ඛණ්ඩය"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"ඊළඟ ඛණ්ඩය"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"වාදනය කරන්න"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> විවෘත කරන්න"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g>ගේ <xliff:g id="SONG_NAME">%1$s</xliff:g> <xliff:g id="APP_LABEL">%3$s</xliff:g> වෙතින් වාදනය කරන්න"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="SONG_NAME">%1$s</xliff:g> <xliff:g id="APP_LABEL">%2$s</xliff:g> වෙතින් වාදනය කරන්න"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"පසුගමනය කරන්න"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"<xliff:g id="DEVICENAME">%1$s</xliff:g> හි වාදනය කිරීමට වඩාත් ළං වන්න"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"<xliff:g id="DEVICENAME">%1$s</xliff:g> හි වාදනය කරමින්"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"අක්‍රියයි, යෙදුම පරීක්ෂා කරන්න"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"හමු නොවිණි"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"පාලනය ලබා ගත නොහැකිය"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"උපාංග 1ක් තෝරන ලදී"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"උපාංග <xliff:g id="COUNT">%1$d</xliff:g>ක් තෝරන ලදී"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(විසන්ධි විය)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"සම්බන්ධ වීමට නොහැකි විය. නැවත උත්සාහ කරන්න."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"මාරු කිරීමට නොහැකිය. නැවත උත්සාහ කිරීමට තට්ටු කරන්න."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"නව උපාංගය යුගල කරන්න"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"නිමැවුම් අංකය"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"නිමැවුම් අංකය පසුරු පුවරුවට පිටපත් කරන ලදි."</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"සියල්ල බලන්න"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ජාල මාරු කිරීමට, ඊතර්නෙට් විසන්ධි කරන්න"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"උපාංග අත්දැකීම වැඩි දියුණු කිරිමට, Wi‑Fi ක්‍රියාවිරහිත විට පවා, ඕනෑම අවස්ථාවක Wi‑Fi ජාල සඳහා ස්කෑන් කිරීමට යෙදුම් සහ සේවාවලට හැකිය. ඔබට මෙය Wi‑Fi ස්කෑන් කිරීමේ සැකසීම් තුළ වෙනස් කළ හැකිය. "<annotation id="link">"වෙනස් කරන්න"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"ගුවන් යානා ප්‍රකාරය ක්‍රියාවිරහිත කරන්න"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"පරිශීලක තෝරන්න"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"පසුබිමින් ධාවනය වෙමින් පවතින යෙදුම්"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"නවත්වන්න"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-si/tiles_states_strings.xml b/packages/SystemUI/res/values-si/tiles_states_strings.xml
index 9445457..fa78ccc 100644
--- a/packages/SystemUI/res/values-si/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-si/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"ක්‍රියාවිරහිතයි"</item>
     <item msgid="460891964396502657">"ක්‍රියාත්මකයි"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"නොමැත"</item>
+    <item msgid="5581384648880018330">"ක්‍රියාවිරහිතයි"</item>
+    <item msgid="8000850843692192257">"ක්‍රියාත්මකයි"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 5ab4026..0838f65 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -252,7 +252,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Nie sú k dispozícii žiadne zariadenia"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Sieť Wi‑Fi nie je pripojená"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Jas"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Inverzia farieb"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inverzia farieb"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"Ďalšie nastavenia"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Používateľské nastavenia"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"Hotovo"</string>
@@ -757,7 +757,7 @@
     <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Zväčšenie celej obrazovky"</string>
     <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Zväčšiť časť obrazovky"</string>
     <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Prepnúť"</string>
-    <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Tlačidlo dostupnosti nahradilo gesto dostupnosti\n\n"<annotation id="link">"Zobraziť nastavenia"</annotation></string>
+    <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Funkcie dostupnosti otvoríte klepnutím. Tlačidlo prispôsobte alebo nahraďte v Nastav.\n\n"<annotation id="link">"Zobraz. nast."</annotation></string>
     <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Ak chcete tlačidlo dočasne skryť, presuňte ho k okraju"</string>
     <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Presunúť doľava nahor"</string>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Presunúť doprava nahor"</string>
@@ -810,10 +810,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Nastavenia"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> od interpreta <xliff:g id="ARTIST_NAME">%2$s</xliff:g> sa prehráva z aplikácie <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> z <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"Prehrať"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"Pozastaviť"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"Predchádzajúca skladba"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"Ďalšia skladba"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Prehrať"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Otvoriť <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Prehrať skladbu <xliff:g id="SONG_NAME">%1$s</xliff:g> od interpreta <xliff:g id="ARTIST_NAME">%2$s</xliff:g> z aplikácie <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Prehrať skladbu <xliff:g id="SONG_NAME">%1$s</xliff:g> z aplikácie <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"Späť"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Ak chcete prehrávať v zariadení <xliff:g id="DEVICENAME">%1$s</xliff:g>, priblížte sa"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"Prehráva sa v zariadení <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Neaktívne, preverte aplikáciu"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Nenájdené"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Ovládač nie je k dispozícii"</string>
@@ -828,7 +835,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 vybrané zariadenie"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"Počet vybraných zariadení: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(odpojené)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Nepodarilo sa pripojiť. Skúste to znova."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Nedá sa prepnúť. Zopakujte klepnutím."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Spárovať nové zariadenie"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Číslo zostavy"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Číslo zostavy bolo skopírované do schránky."</string>
@@ -893,8 +900,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"Zobraziť všetko"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Ak chcete prepnúť siete, odpojte ethernet"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Aplikácie a služby môžu kedykoľvek vyhľadávať siete Wi‑Fi (a to aj vtedy, keď je pripojenie Wi‑Fi vypnuté), čím zlepšujú prostredie v zariadení. Môžete to zmeniť v nastaveniach vyhľadávania sietí Wi‑Fi. "<annotation id="link">"Zmeniť"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Vypnúť režim v lietadle"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Vyberte používateľa"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Aplikácie spustené na pozadí"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Ukončiť"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sk/tiles_states_strings.xml b/packages/SystemUI/res/values-sk/tiles_states_strings.xml
index b7d37c8..1920f04 100644
--- a/packages/SystemUI/res/values-sk/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-sk/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"Vypnuté"</item>
     <item msgid="460891964396502657">"Zapnuté"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"Nedostupné"</item>
+    <item msgid="5581384648880018330">"Vypnuté"</item>
+    <item msgid="8000850843692192257">"Zapnuté"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index f00bf38..e497d51 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -252,7 +252,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Na voljo ni nobene naprave"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Povezava Wi-Fi ni vzpostavljena"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Svetlost"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Inverzija barv"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inverzija barv"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"Več nastavitev"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Uporabniške nastavitve"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"Končano"</string>
@@ -757,7 +757,7 @@
     <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Povečanje celotnega zaslona"</string>
     <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Povečava dela zaslona"</string>
     <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Stikalo"</string>
-    <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Gumb za funkcije za ljudi s posebnimi potrebami je zamenjal pripadajočo potezo.\n\n"<annotation id="link">"Ogled nastavitev"</annotation></string>
+    <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Dotaknite se za funkcije za ljudi s posebnimi potrebami. Ta gumb lahko prilagodite ali zamenjate v nastavitvah.\n\n"<annotation id="link">"Ogled nastavitev"</annotation></string>
     <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Če želite gumb začasno skriti, ga premaknite ob rob."</string>
     <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Premakni zgoraj levo"</string>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Premakni zgoraj desno"</string>
@@ -810,10 +810,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Nastavitve"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"Skladba <xliff:g id="SONG_NAME">%1$s</xliff:g> izvajalca <xliff:g id="ARTIST_NAME">%2$s</xliff:g> se predvaja iz aplikacije <xliff:g id="APP_LABEL">%3$s</xliff:g>."</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> od <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"Predvajaj"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"Začasno zaustavi"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"Prejšnja skladba"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"Naslednja skladba"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Predvajaj"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Odpri aplikacijo <xliff:g id="APP_LABEL">%1$s</xliff:g>."</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Predvajaj skladbo <xliff:g id="SONG_NAME">%1$s</xliff:g> izvajalca <xliff:g id="ARTIST_NAME">%2$s</xliff:g> iz aplikacije <xliff:g id="APP_LABEL">%3$s</xliff:g>."</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Predvajaj skladbo <xliff:g id="SONG_NAME">%1$s</xliff:g> iz aplikacije <xliff:g id="APP_LABEL">%2$s</xliff:g>."</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"Razveljavi"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Za predvajanje v napravi <xliff:g id="DEVICENAME">%1$s</xliff:g> bolj približajte telefon."</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"Predvajanje v napravi <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Neaktivno, poglejte aplikacijo"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Ni mogoče najti"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrolnik ni na voljo"</string>
@@ -828,7 +835,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"Izbrana je ena naprava"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"Izbranih je toliko naprav: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(povezava je prekinjena)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Povezave ni bilo mogoče vzpostaviti. Poskusite znova."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Preklop ni mogoč. Če želite poskusiti znova, se dotaknite."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Seznanitev nove naprave"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Delovna različica"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Delovna različica je bila kopirana v odložišče."</string>
@@ -893,8 +900,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"Prikaz vseh omrežij"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Če želite preklopiti omrežje, prekinite ethernetno povezavo."</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Za izboljšano izkušnjo pri uporabi naprave lahko aplikacije in storitve kadar koli iščejo omrežja Wi‑Fi, tudi ko je Wi‑Fi izklopljen. To lahko spremenite v nastavitvah iskanja omrežij Wi-Fi. "<annotation id="link">"Spremeni"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Izklopi način za letalo"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Izberite uporabnika"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Aplikacije z izvajanjem v ozadju"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Ustavi"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sl/tiles_states_strings.xml b/packages/SystemUI/res/values-sl/tiles_states_strings.xml
index 28e3917..924ec58 100644
--- a/packages/SystemUI/res/values-sl/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-sl/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"Izklopljeno"</item>
     <item msgid="460891964396502657">"Vklopljeno"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"Ni na voljo"</item>
+    <item msgid="5581384648880018330">"Izklopljeno"</item>
+    <item msgid="8000850843692192257">"Vklopljeno"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 413bcec..d6d5047 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Nuk ofrohet për përdorim asnjë pajisje"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi-Fi nuk është lidhur"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Ndriçimi"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Shkëmbe ngjyrat"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Anasjellja e ngjyrës"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"Cilësime të tjera"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Cilësimet e përdoruesit"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"U krye"</string>
@@ -747,7 +747,7 @@
     <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Zmadho ekranin e plotë"</string>
     <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Zmadho një pjesë të ekranit"</string>
     <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Ndërro"</string>
-    <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Butoni i qasshmërisë zëvendësoi gjestin e qasshmërisë\n\n"<annotation id="link">"Shiko cilësimet"</annotation></string>
+    <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Trokit dhe hap veçoritë e qasshmërisë. Modifiko ose ndërro butonin te \"Cilësimet\".\n\n"<annotation id="link">"Shih cilësimet"</annotation></string>
     <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Zhvendose butonin në skaj për ta fshehur përkohësisht"</string>
     <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Zhvendos lart majtas"</string>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Zhvendos lart djathtas"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Cilësimet"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> nga <xliff:g id="ARTIST_NAME">%2$s</xliff:g> po luhet nga <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> nga <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"Luaj"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"Vendos në pauzë"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"Pjesa muzikore e mëparshme"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"Pjesa tjetër muzikore"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Luaj"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Hap <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Luaj <xliff:g id="SONG_NAME">%1$s</xliff:g> nga <xliff:g id="ARTIST_NAME">%2$s</xliff:g> nga <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Luaj <xliff:g id="SONG_NAME">%1$s</xliff:g> nga <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"Zhbëj"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Afrohu për të luajtur në <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"Po luhet në <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Joaktive, kontrollo aplikacionin"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Nuk u gjet"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrolli është i padisponueshëm"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 pajisje e zgjedhur"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> pajisje të zgjedhura"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(shkëputur)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Nuk mund të lidhej. Provo sërish."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Nuk mund të ndërrohet. Trokit për të provuar përsëri."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Çifto pajisjen e re"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Numri i ndërtimit"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Numri i ndërtimit u kopjua te kujtesa e fragmenteve"</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"Shiko të gjitha"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Për të ndërruar rrjetet, shkëput Ethernet-in"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Për të përmirësuar përvojën e pajisjes, aplikacionet dhe shërbimet mund të vazhdojnë të skanojnë për rrjete Wi-Fi në çdo kohë, edhe kur Wi-Fi është joaktiv. Mund ta ndryshosh këtë te cilësimet e skanimit të Wi-Fi. "<annotation id="link">"Ndrysho"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Çaktivizo modalitetin e aeroplanit"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Zgjidh përdoruesin"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Aplikacionet që ekzekutohen në sfond"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Ndalo"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sq/tiles_states_strings.xml b/packages/SystemUI/res/values-sq/tiles_states_strings.xml
index 6643e04..34879ce 100644
--- a/packages/SystemUI/res/values-sq/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-sq/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"Joaktiv"</item>
     <item msgid="460891964396502657">"Aktiv"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"Nuk ofrohet"</item>
+    <item msgid="5581384648880018330">"Joaktiv"</item>
+    <item msgid="8000850843692192257">"Aktiv"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index b5cd94b..dae3070 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -251,7 +251,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Није доступан ниједан уређај"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"WiFi није повезан"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Осветљеност"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Обрни боје"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Инверзија боја"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"Још подешавања"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Корисничка подешавања"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"Готово"</string>
@@ -752,7 +752,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="5217151214439341902">"Додирните за функције приступачности. Прилагодите или замените ово дугме у Подешавањима.\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>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Премести горе десно"</string>
@@ -804,10 +804,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Подешавања"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> извођача <xliff:g id="ARTIST_NAME">%2$s</xliff:g> се пушта из апликације <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> од <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"Пусти"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"Паузирај"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"Претходна песма"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"Следећа песма"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Пусти"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Отворите <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Пустите <xliff:g id="SONG_NAME">%1$s</xliff:g> извођача <xliff:g id="ARTIST_NAME">%2$s</xliff:g> из апликације <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Пустите <xliff:g id="SONG_NAME">%1$s</xliff:g> из апликације <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"Опозови"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Приближите да бисте пуштали музику на: <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"Пушта се на: <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Неактивно. Видите апликацију"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Није пронађено"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Контрола није доступна"</string>
@@ -822,7 +829,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"Изабран је 1 уређај"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"Изабраних уређаја: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(веза је прекинута)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Повезивање није успело. Пробајте поново."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Пребацивање није успело. Пробајте поново."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Упари нови уређај"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Број верзије"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Број верзије је копиран у привремену меморију."</string>
@@ -887,8 +894,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"Погледајте све"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Да бисте променили мрежу, прекините етернет везу"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Ради бољег доживљаја уређаја, апликације и услуге и даље могу да траже WiFi мреже у било ком тренутку, чак и када је WiFi искључен. То можете да промените у подешавањима WiFi скенирања. "<annotation id="link">"Промените"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Искључите режим рада у авиону"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Изаберите корисника"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Апликације покренуте у позадини"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Заустави"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sr/tiles_states_strings.xml b/packages/SystemUI/res/values-sr/tiles_states_strings.xml
index 63542da..855b84b 100644
--- a/packages/SystemUI/res/values-sr/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-sr/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"Искључено"</item>
     <item msgid="460891964396502657">"Укључено"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"Недоступно"</item>
+    <item msgid="5581384648880018330">"Искључено"</item>
+    <item msgid="8000850843692192257">"Укључено"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 1bae752..668e7d3 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Inga tillgängliga enheter"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Ej ansluten till wifi"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Ljusstyrka"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Invertera färger"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Färginvertering"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"Fler inställningar"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Användarinställningar"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"Klart"</string>
@@ -747,7 +747,7 @@
     <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Förstora hela skärmen"</string>
     <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Förstora en del av skärmen"</string>
     <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Reglage"</string>
-    <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Tillgänglighetsknappen har ersatt tillgänglighetsrörelsen\n\n"<annotation id="link">"Visa inställningarna"</annotation></string>
+    <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Tryck för att öppna tillgänglighetsfunktioner. Anpassa/ersätt knappen i Inställningar.\n\n"<annotation id="link">"Inställningar"</annotation></string>
     <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Flytta knappen till kanten för att dölja den tillfälligt"</string>
     <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Flytta högst upp till vänster"</string>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Flytta högst upp till höger"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Inställningar"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> med <xliff:g id="ARTIST_NAME">%2$s</xliff:g> spelas upp från <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> av <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"Spela upp"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"Pausa"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"Föregående spår"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"Nästa spår"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Spela upp"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Öppna <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Spela upp <xliff:g id="SONG_NAME">%1$s</xliff:g> med <xliff:g id="ARTIST_NAME">%2$s</xliff:g> från <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Spela upp <xliff:g id="SONG_NAME">%1$s</xliff:g> från <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"Ångra"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Flytta närmare för att spela upp på <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"Spelas upp på <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Inaktiv, kolla appen"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Hittades inte"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Styrning är inte tillgänglig"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 enhet har valts"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> enheter har valts"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(frånkopplad)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Det gick inte att ansluta. Försök igen."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Misslyckat byte. Tryck och försök igen."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Parkoppla en ny enhet"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Versionsnummer"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Versionsnumret har kopierats till urklipp."</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"Visa alla"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Koppla bort Ethernet för att växla nätverk"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"I syfte att förbättra upplevelsen med enheten kan appar och tjänster fortfarande söka efter wifi-nätverk när som helst, även om wifi har inaktiverats. "<annotation id="link">"Ändra"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Inaktivera flygplansläge"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Välj användare"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Appar som körs i bakgrunden"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Stoppa"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sv/tiles_states_strings.xml b/packages/SystemUI/res/values-sv/tiles_states_strings.xml
index e009e0b..b071b91 100644
--- a/packages/SystemUI/res/values-sv/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-sv/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"Av"</item>
     <item msgid="460891964396502657">"På"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"Inte tillgänglig"</item>
+    <item msgid="5581384648880018330">"Av"</item>
+    <item msgid="8000850843692192257">"På"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index c4e9540..fad086ad 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Hakuna vifaa vilivyopatikana"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi-Fi haijaunganishwa"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Ung\'avu"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Pindua rangi"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Ugeuzaji rangi"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"Mipangilio zaidi"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Mipangilio ya mtumiaji"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"Nimemaliza"</string>
@@ -747,7 +747,7 @@
     <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Kuza skrini nzima"</string>
     <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Kuza sehemu ya skrini"</string>
     <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Swichi"</string>
-    <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Kitufe cha zana za ufikivu kimechukua nafasi ya ishara ya ufikivu\n\n"<annotation id="link">"Angalia mipangilio"</annotation></string>
+    <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Gusa ili ufungue vipengele vya ufikivu. Weka mapendeleo au ubadilishe kitufe katika Mipangilio.\n\n"<annotation id="link">"Angalia mipangilio"</annotation></string>
     <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Sogeza kitufe kwenye ukingo ili ukifiche kwa muda"</string>
     <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Sogeza juu kushoto"</string>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Sogeza juu kulia"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Mipangilio"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> ulioimbwa na <xliff:g id="ARTIST_NAME">%2$s</xliff:g> unacheza katika <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> kati ya <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"Cheza"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"Simamisha"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"Wimbo uliotangulia"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"Wimbo unaofuata"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Cheza"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Fungua <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Cheza <xliff:g id="SONG_NAME">%1$s</xliff:g> ulioimbwa na <xliff:g id="ARTIST_NAME">%2$s</xliff:g> katika <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Cheza <xliff:g id="SONG_NAME">%1$s</xliff:g> katika <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"Tendua"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Sogea karibu ili ucheze kwenye <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"Inacheza kwenye <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Haitumiki, angalia programu"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Hakipatikani"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Kidhibiti hakipatikani"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"Umechagua kifaa 1"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"Umechagua vifaa <xliff:g id="COUNT">%1$d</xliff:g>"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(imetenganishwa)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Imeshindwa kuunganisha. Jaribu tena."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Imeshindwa kubadilisha. Gusa ili ujaribu tena."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Oanisha kifaa kipya"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Nambari ya muundo"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Nambari ya muundo imewekwa kwenye ubao wa kunakili."</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"Angalia yote"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Ili kubadili mitandao, tenganisha ethaneti"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Ili kuboresha hali ya matumizi ya kifaa, programu na huduma bado zinaweza kutafuta mitandao ya Wi‑Fi wakati wowote, hata wakati umezima Wi‑Fi. Unaweza kubadilisha mipangilio hii katika mipangilio ya kutafuta Wi-Fi. "<annotation id="link">"Badilisha"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Zima hali ya ndegeni"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Chagua mtumiaji"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Programu zinazotumika chinichini"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Simamisha"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sw/tiles_states_strings.xml b/packages/SystemUI/res/values-sw/tiles_states_strings.xml
index beabdc4..a92c7f9 100644
--- a/packages/SystemUI/res/values-sw/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-sw/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"Imezimwa"</item>
     <item msgid="460891964396502657">"Imewashwa"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"Haipatikani"</item>
+    <item msgid="5581384648880018330">"Imezimwa"</item>
+    <item msgid="8000850843692192257">"Imewashwa"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index f8af3a6..10912be 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"சாதனங்கள் இல்லை"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"வைஃபை இணைக்கப்படவில்லை"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"ஒளிர்வு"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"வண்ணங்களை மாற்று"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"கலர் இன்வெர்ஷன்"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"அமைப்பில் மாற்று"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"பயனர் அமைப்புகள்"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"முடிந்தது"</string>
@@ -747,7 +747,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="5217151214439341902">"அணுகல்தன்மை அம்சத்தை திறக்க தட்டவும். அமைப்பில் பட்டனை பிரத்தியேகமாக்கலாம்/மாற்றலாம்.\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>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"மேலே வலதுபுறத்திற்கு நகர்த்து"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"அமைப்புகள்"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> இன் <xliff:g id="SONG_NAME">%1$s</xliff:g> பாடல் <xliff:g id="APP_LABEL">%3$s</xliff:g> ஆப்ஸில் பிளேயாகிறது"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> / <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"பிளே செய்"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"இடைநிறுத்து"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"முந்தைய டிராக்"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"அடுத்த டிராக்"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"இயக்குதல்"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> ஆப்ஸைத் திறங்கள்"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> இன் <xliff:g id="SONG_NAME">%1$s</xliff:g> பாடலை <xliff:g id="APP_LABEL">%3$s</xliff:g> ஆப்ஸில் பிளேசெய்"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="SONG_NAME">%1$s</xliff:g> பாடலை <xliff:g id="APP_LABEL">%2$s</xliff:g> ஆப்ஸில் பிளேசெய்"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"செயல்தவிர்"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"<xliff:g id="DEVICENAME">%1$s</xliff:g> சாதனத்தில் பிளே செய்ய உங்கள் சாதனத்தை அருகில் எடுத்துச் செல்லவும்"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"<xliff:g id="DEVICENAME">%1$s</xliff:g> சாதனத்தில் பிளே ஆகிறது"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"செயலில் இல்லை , சரிபார்க்கவும்"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"இல்லை"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"கட்டுப்பாடு இல்லை"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 சாதனம் தேர்ந்தெடுக்கப்பட்டுள்ளது"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> சாதனங்கள் தேர்ந்தெடுக்கப்பட்டுள்ளன"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(துண்டிக்கப்பட்டது)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"இணைக்க முடியவில்லை. மீண்டும் முயலவும்."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"இணைக்க முடியவில்லை. மீண்டும் முயல தட்டவும்."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"புதிய சாதனத்தை இணைத்தல்"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"பதிப்பு எண்"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"பதிப்பு எண் கிளிப்போர்டுக்கு நகலெடுக்கப்பட்டது."</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"அனைத்தையும் காட்டு"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"நெட்வொர்க்குகளை மாற்ற ஈதர்நெட் இணைப்பைத் துண்டிக்கவும்"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"சாதன அனுபவத்தை மேம்படுத்த, வைஃபை ஆஃப் செய்யப்பட்டிருந்தாலும்கூட எந்த நேரத்திலும் ஆப்ஸும் சேவைகளும் வைஃபை நெட்வொர்க்குகளைத் தேடலாம். வைஃபை ஸ்கேனிங் அமைப்புகளில் இதை மாற்றிக் கொள்ளலாம். "<annotation id="link">"மாற்று"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"விமானப் பயன்முறையை முடக்கும்"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"பயனரைத் தேர்வுசெய்க"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"பின்னணியில் இயங்கும் ஆப்ஸ்"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"நிறுத்து"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ta/tiles_states_strings.xml b/packages/SystemUI/res/values-ta/tiles_states_strings.xml
index 9f2a2e9..f3ba1a1 100644
--- a/packages/SystemUI/res/values-ta/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ta/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"முடக்கப்பட்டுள்ளது"</item>
     <item msgid="460891964396502657">"இயக்கப்பட்டுள்ளது"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"கிடைக்கவில்லை"</item>
+    <item msgid="5581384648880018330">"ஆஃப்"</item>
+    <item msgid="8000850843692192257">"ஆன்"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 77d076d..abba928 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"పరికరాలు ఏవీ అందుబాటులో లేవు"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi‑Fi కనెక్ట్ కాలేదు"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"ప్రకాశం"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"కలర్ మార్పిడి"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"కలర్ మార్పిడి"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"మరిన్ని సెట్టింగ్‌లు"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"యూజర్ సెట్టింగ్‌లు"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"పూర్తయింది"</string>
@@ -747,7 +747,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="5217151214439341902">"యాక్సెసిబిలిటీ ఫీచర్‌లను తెరవడానికి ట్యాప్ చేయండి. సెట్టింగ్‌లలో ఈ బటన్‌ను అనుకూలీకరించండి లేదా రీప్లేస్ చేయండి.\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>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"ఎగువ కుడి వైపునకు తరలించు"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"సెట్టింగ్‌లు"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> పాడిన <xliff:g id="SONG_NAME">%1$s</xliff:g> <xliff:g id="APP_LABEL">%3$s</xliff:g> నుండి ప్లే అవుతోంది"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="TOTAL_TIME">%2$s</xliff:g>లో <xliff:g id="ELAPSED_TIME">%1$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"ప్లే చేయండి"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"పాజ్ చేయండి"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"మునుపటి ట్రాక్"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"తర్వాతి ట్రాక్"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"ప్లే చేయండి"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g>ను తెరవండి"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="APP_LABEL">%3$s</xliff:g> నుండి <xliff:g id="ARTIST_NAME">%2$s</xliff:g> పాడిన <xliff:g id="SONG_NAME">%1$s</xliff:g>‌ను ప్లే చేయండి"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="APP_LABEL">%2$s</xliff:g> నుండి <xliff:g id="SONG_NAME">%1$s</xliff:g>‌ను ప్లే చేయండి"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"చర్య రద్దు"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"<xliff:g id="DEVICENAME">%1$s</xliff:g>లో ప్లే చేయడానికి దగ్గరగా వెళ్లండి"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"<xliff:g id="DEVICENAME">%1$s</xliff:g>లో ప్లే అవుతోంది"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"ఇన్‌యాక్టివ్, యాప్ చెక్ చేయండి"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"కనుగొనబడలేదు"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"కంట్రోల్ అందుబాటులో లేదు"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 పరికరం ఎంచుకోబడింది"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> పరికరాలు ఎంచుకోబడ్డాయి"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(డిస్కనెక్ట్ అయ్యింది)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"కనెక్ట్ చేయడం సాధ్యపడలేదు. మళ్లీ ట్రై చేయండి."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"స్విచ్ చేయడం సాధ్యం కాదు. మళ్ళీ ట్రై చేయడానికి ట్యాప్ చేయండి."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"కొత్త పరికరాన్ని పెయిర్ చేయండి"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"బిల్డ్ నంబర్"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"బిల్డ్ నంబర్, క్లిప్‌బోర్డ్‌కు కాపీ చేయబడింది."</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"అన్నీ చూడండి"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"నెట్‌వర్క్‌లను మార్చడానికి, ఈథర్‌నెట్‌ను డిస్‌కనెక్ట్ చేయండి"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"పరికర అనుభవాన్ని మెరుగుపరచడానికి, Wi‑Fi ఆఫ్‌లో ఉన్నప్పుడు కూడా, ఏ సమయంలో అయినా ఇప్పటికీ Wi‑Fi నెట్‌వర్క్‌ల కోసం యాప్‌లు, సర్వీస్‌లు స్కాన్ చేయగలవు. మీరు దీనిని Wi‑Fi స్కానింగ్ సెట్టింగ్‌లలో మార్చవచ్చు. "<annotation id="link">"మార్చండి"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"విమానం మోడ్‌ను ఆఫ్ చేయండి"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"యూజర్‌ను ఎంచుకోండి"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"యాప్‌లు బ్యాక్‌గ్రౌండ్‌లో రన్ అవుతున్నాయి"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"ఆపివేయండి"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-te/tiles_states_strings.xml b/packages/SystemUI/res/values-te/tiles_states_strings.xml
index c23436f..bed919f 100644
--- a/packages/SystemUI/res/values-te/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-te/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"ఆఫ్"</item>
     <item msgid="460891964396502657">"ఆన్"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"అందుబాటులో లేదు"</item>
+    <item msgid="5581384648880018330">"ఆఫ్‌లో ఉంది"</item>
+    <item msgid="8000850843692192257">"ఆన్‌లో ఉంది"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-television/config.xml b/packages/SystemUI/res/values-television/config.xml
index 2f0957c..2eff692 100644
--- a/packages/SystemUI/res/values-television/config.xml
+++ b/packages/SystemUI/res/values-television/config.xml
@@ -42,6 +42,7 @@
         <item>@string/config_systemUIVendorServiceComponent</item>
         <item>com.android.systemui.SliceBroadcastRelayHandler</item>
         <item>com.android.systemui.statusbar.notification.InstantAppNotifier</item>
+        <item>com.android.systemui.accessibility.WindowMagnification</item>
         <item>com.android.systemui.toast.ToastUI</item>
         <item>com.android.systemui.wmshell.WMShell</item>
         <item>com.android.systemui.media.systemsounds.HomeSoundEffectController</item>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 15215e3..a586f76f 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"ไม่มีอุปกรณ์ที่สามารถใช้ได้"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"ไม่ได้เชื่อมต่อ Wi-Fi"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"ความสว่าง"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"กลับสี"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"การกลับสี"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"การตั้งค่าเพิ่มเติม"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"การตั้งค่าของผู้ใช้"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"เสร็จสิ้น"</string>
@@ -747,7 +747,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="5217151214439341902">"แตะเพื่อเปิดฟีเจอร์การช่วยเหลือพิเศษ ปรับแต่งหรือแทนที่ปุ่มนี้ในการตั้งค่า\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>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"ย้ายไปด้านขวาบน"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"การตั้งค่า"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"กำลังเปิดเพลง <xliff:g id="SONG_NAME">%1$s</xliff:g> ของ <xliff:g id="ARTIST_NAME">%2$s</xliff:g> จาก <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> จาก <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"เล่น"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"หยุดชั่วคราว"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"แทร็กก่อนหน้า"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"เพลงถัดไป"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"เล่น"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"เปิด <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"เปิดเพลง <xliff:g id="SONG_NAME">%1$s</xliff:g> ของ <xliff:g id="ARTIST_NAME">%2$s</xliff:g> จาก <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"เปิดเพลง <xliff:g id="SONG_NAME">%1$s</xliff:g> จาก <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"เลิกทำ"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"ขยับเข้ามาใกล้ขึ้นเพื่อเล่นใน <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"กำลังเล่นใน <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"ไม่มีการใช้งาน โปรดตรวจสอบแอป"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"ไม่พบ"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"ใช้การควบคุมไม่ได้"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"เลือกอุปกรณ์ไว้ 1 รายการ"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"เลือกอุปกรณ์ไว้ <xliff:g id="COUNT">%1$d</xliff:g> รายการ"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(ยกเลิกการเชื่อมต่อแล้ว)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"เชื่อมต่อไม่ได้ ลองใหม่"</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"เปลี่ยนไม่ได้ แตะเพื่อลองอีกครั้ง"</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"จับคู่อุปกรณ์ใหม่"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"หมายเลขบิลด์"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"คัดลอกหมายเลขบิลด์ไปยังคลิปบอร์ดแล้ว"</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"ดูทั้งหมด"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ตัดการเชื่อมต่ออีเทอร์เน็ตเพื่อสลับเครือข่าย"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"เพื่อปรับปรุงประสบการณ์การใช้อุปกรณ์ แอปและบริการต่างๆ จะยังคงสแกนหาเครือข่าย Wi‑Fi ได้ทุกเมื่อแม้ว่า Wi‑Fi จะปิดอยู่ คุณเปลี่ยนตัวเลือกนี้ได้ในการตั้งค่าการสแกนหา Wi-Fi "<annotation id="link">"เปลี่ยน"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"ปิดโหมดบนเครื่องบิน"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"เลือกผู้ใช้"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"แอปที่ทำงานอยู่เบื้องหลัง"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"หยุด"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-th/tiles_states_strings.xml b/packages/SystemUI/res/values-th/tiles_states_strings.xml
index 850fb7c..d5591b2 100644
--- a/packages/SystemUI/res/values-th/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-th/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"ปิด"</item>
     <item msgid="460891964396502657">"เปิด"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"ไม่พร้อมใช้งาน"</item>
+    <item msgid="5581384648880018330">"ปิด"</item>
+    <item msgid="8000850843692192257">"เปิด"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index a944124..42eed44 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Walang available na mga device"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Hindi nakakonekta sa Wi-Fi"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Brightness"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"I-invert ang mga kulay"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Pag-invert ng kulay"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"Higit pang setting"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Mga setting ng user"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"Tapos na"</string>
@@ -747,7 +747,7 @@
     <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"I-magnify ang buong screen"</string>
     <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"I-magnify ang isang bahagi ng screen"</string>
     <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Switch"</string>
-    <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Pinalitan ng button ng accessibility ang galaw ng accessibility\n\n"<annotation id="link">"Tingnan ang mga setting"</annotation></string>
+    <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"I-tap, buksan mga feature ng accessibility. I-customize o palitan button sa Mga Setting.\n\n"<annotation id="link">"Tingnan ang mga setting"</annotation></string>
     <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Ilipat ang button sa gilid para pansamantala itong itago"</string>
     <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Ilipat sa kaliwa sa itaas"</string>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Ilipat sa kanan sa itaas"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Mga Setting"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"Nagpe-play ang <xliff:g id="SONG_NAME">%1$s</xliff:g> ni/ng <xliff:g id="ARTIST_NAME">%2$s</xliff:g> mula sa <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> sa <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"I-play"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"I-pause"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"Nakaraang track"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"Susunod na track"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"I-play"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Buksan ang <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"I-play ang <xliff:g id="SONG_NAME">%1$s</xliff:g> ni/ng <xliff:g id="ARTIST_NAME">%2$s</xliff:g> mula sa <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"I-play ang <xliff:g id="SONG_NAME">%1$s</xliff:g> mula sa <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"I-undo"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Lumapit pa para mag-play sa <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"Nagpe-play sa <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Hindi aktibo, tingnan ang app"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Hindi nahanap"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Hindi available ang kontrol"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 device ang napili"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> (na) device ang napili"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(nadiskonekta)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Hindi makakonekta. Subukan ulit."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Hindi makalipat. I-tap para subukan ulit."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Magpares ng bagong device"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Numero ng build"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Nakopya sa clipboard ang numero ng build."</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"Tingnan lahat"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Para lumipat ng network, idiskonekta ang ethernet"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Para pahusayin ang karanasan sa device, puwede pa ring mag-scan ng mga Wi-Fi network ang mga app at serbisyo anumang oras, kahit habang naka-off ang Wi‑Fi. Mababago mo ito sa mga setting ng pag-scan ng Wi-Fi. "<annotation id="link">"Baguhin"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"I-off ang airplane mode"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Pumili ng user"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Mga app na tumatakbo sa background"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Ihinto"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-tl/tiles_states_strings.xml b/packages/SystemUI/res/values-tl/tiles_states_strings.xml
index dbf54ec..c601d2f 100644
--- a/packages/SystemUI/res/values-tl/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-tl/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"Naka-off"</item>
     <item msgid="460891964396502657">"Naka-on"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"Hindi available"</item>
+    <item msgid="5581384648880018330">"Naka-off"</item>
+    <item msgid="8000850843692192257">"Naka-on"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 98b15d9..f79420e 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Kullanılabilir cihaz yok"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Kablosuz ağ bağlı değil"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Parlaklık"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Renkleri çevir"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Rengi ters çevirme"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"Diğer ayarlar"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Kullanıcı ayarları"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"Bitti"</string>
@@ -747,7 +747,7 @@
     <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Tam ekran büyütme"</string>
     <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Ekranın bir parçasını büyütün"</string>
     <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Geç"</string>
-    <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Erişilebilirlik hareketi, Erişilebilirlik düğmesi ile değiştirildi\n\n"<annotation id="link">"Ayarları görüntüle"</annotation></string>
+    <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Erişilebilirlik özelliklerini açmak için dokunun. Bu düğmeyi Ayarlar\'dan özelleştirin veya değiştirin.\n\n"<annotation id="link">"Ayarları göster"</annotation></string>
     <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Düğmeyi geçici olarak gizlemek için kenara taşıyın"</string>
     <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Sol üste taşı"</string>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Sağ üste taşı"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Ayarlar"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g> uygulamasından <xliff:g id="ARTIST_NAME">%2$s</xliff:g>, <xliff:g id="SONG_NAME">%1$s</xliff:g> şarkısı çalıyor"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g>/<xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"Çal"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"Duraklat"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"Önceki parça"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"Sonraki parça"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Oynat"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> uygulamasını aç"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="APP_LABEL">%3$s</xliff:g> uygulamasından <xliff:g id="ARTIST_NAME">%2$s</xliff:g>, <xliff:g id="SONG_NAME">%1$s</xliff:g> şarkısını çal"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="APP_LABEL">%2$s</xliff:g> uygulamasından <xliff:g id="SONG_NAME">%1$s</xliff:g> şarkısını çal"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"Geri al"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"<xliff:g id="DEVICENAME">%1$s</xliff:g> cihazında çalmak için yaklaşın"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"<xliff:g id="DEVICENAME">%1$s</xliff:g> cihazında çalınıyor"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Devre dışı, uygulamaya bakın"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Bulunamadı"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrol kullanılamıyor"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 cihaz seçildi"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> cihaz seçildi"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(bağlantı kesildi)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Bağlanılamadı. Tekrar deneyin."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Geçiş yapılamıyor. Tekrar denemek için dokunun."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Yeni cihaz eşle"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Derleme numarası"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Derleme numarası panoya kopyalandı."</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"Tümünü göster"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Ağ değiştirmek için ethernet bağlantısını kesin"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Uygulamalar ve hizmetler, cihaz deneyimini iyileştirmek için Kablosuz özelliği kapalı bile olsa kablosuz ağlar herhangi bir zamanda tarayabilir. Bunu kablosuz ağ taraması ayarlarından değiştirebilirsiniz. "<annotation id="link">"Değiştir"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Uçak modunu kapat"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Kullanıcı seçin"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Arka planda çalışan uygulamalar"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Durdur"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-tr/tiles_states_strings.xml b/packages/SystemUI/res/values-tr/tiles_states_strings.xml
index 9eded7c..17ce6b3 100644
--- a/packages/SystemUI/res/values-tr/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-tr/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"Kapalı"</item>
     <item msgid="460891964396502657">"Açık"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"Kullanılamıyor"</item>
+    <item msgid="5581384648880018330">"Kapalı"</item>
+    <item msgid="8000850843692192257">"Açık"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 6535ecb..17a3ce8 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -252,7 +252,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Немає пристроїв"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi-Fi не під’єднано"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Яскравість"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Інвертовані кольори"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Інверсія кольорів"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"Більше налаштувань"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Налаштування користувача"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"Готово"</string>
@@ -757,7 +757,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="5217151214439341902">"Кнопка спеціальних можливостей. Змініть або замініть її в Налаштуваннях.\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>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Перемістити праворуч угору"</string>
@@ -810,10 +810,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Налаштування"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"Пісня \"<xliff:g id="SONG_NAME">%1$s</xliff:g>\", яку виконує <xliff:g id="ARTIST_NAME">%2$s</xliff:g>, грає в додатку <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> з <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"Відтворити"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"Призупинити"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"Попередня композиція"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"Наступна композиція"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Відтворення"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Відкрити додаток <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Увімкнути пісню \"<xliff:g id="SONG_NAME">%1$s</xliff:g>\", яку виконує <xliff:g id="ARTIST_NAME">%2$s</xliff:g>, у додатку <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Увімкнути пісню \"<xliff:g id="SONG_NAME">%1$s</xliff:g>\" у додатку <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"Відмінити"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Щоб відтворити на пристрої <xliff:g id="DEVICENAME">%1$s</xliff:g>, наблизьтеся до нього"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"Відтворюється на пристрої <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Неактивно, перейдіть у додаток"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Не знайдено"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Елемент керування недоступний"</string>
@@ -828,7 +835,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"Вибрано 1 пристрій"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"Вибрано пристроїв: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(від’єднано)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Не вдалося підключитися. Повторіть спробу."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Не вдалося змінити підключення. Натисніть, щоб повторити спробу."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Підключити новий пристрій"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Номер складання"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Номер складання скопійовано в буфер обміну."</string>
@@ -893,8 +900,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"Показати все"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Щоб вибрати іншу мережу, від’єднайте кабель Ethernet"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Щоб користуватися пристроєм було зручніше, додатки й сервіси можуть шукати бездротові мережі, навіть якщо Wi-Fi вимкнено. Це налаштування можна змінити в параметрах пошуку мереж Wi-Fi. "<annotation id="link">"Змінити"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Вимкнути режим польоту"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Виберіть користувача"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Додатки, що працюють у фоновому режимі"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Зупинити"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-uk/tiles_states_strings.xml b/packages/SystemUI/res/values-uk/tiles_states_strings.xml
index c9da2b4..6f9ef21 100644
--- a/packages/SystemUI/res/values-uk/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-uk/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"Вимкнено"</item>
     <item msgid="460891964396502657">"Увімкнено"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"Недоступно"</item>
+    <item msgid="5581384648880018330">"Вимкнено"</item>
+    <item msgid="8000850843692192257">"Увімкнено"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 0c46c17..350aaba 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"کوئی آلات دستیاب نہیں ہیں"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"‏Wi-Fi سے منسلک نہیں ہے"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"چمکیلا پن"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"رنگ پلٹیں"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"رنگوں کی تقلیب"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"مزید ترتیبات"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"صارف کی ترتیبات"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"ہو گیا"</string>
@@ -747,7 +747,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="5217151214439341902">"ایکسیسبیلٹی خصوصیات کھولنے کے لیے تھپتھپائیں۔ ترتیبات میں اس بٹن کو حسب ضرورت بنائیں یا تبدیل کریں۔\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>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"اوپر دائیں جانب لے جائيں"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"ترتیبات"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g> سے <xliff:g id="ARTIST_NAME">%2$s</xliff:g> کا <xliff:g id="SONG_NAME">%1$s</xliff:g> چل رہا ہے"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> از <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"چلائیں"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"روکیں"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"پچھلا ٹریک"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"اگلا ٹریک"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"چلائیں"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> کھولیں"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="APP_LABEL">%3$s</xliff:g> سے <xliff:g id="ARTIST_NAME">%2$s</xliff:g> کا <xliff:g id="SONG_NAME">%1$s</xliff:g> چلائیں"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="APP_LABEL">%2$s</xliff:g> سے <xliff:g id="SONG_NAME">%1$s</xliff:g> چلائیں"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"کالعدم کریں"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"<xliff:g id="DEVICENAME">%1$s</xliff:g> پر چلانے کے لیے قریب کریں"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"<xliff:g id="DEVICENAME">%1$s</xliff:g> پر چل رہا ہے"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"غیر فعال، ایپ چیک کریں"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"نہیں ملا"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"کنٹرول دستیاب نہیں ہے"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 آلہ منتخب کیا گیا"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> آلات منتخب کیے گئے"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(غیر منسلک ہے)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"منسلک نہیں ہو سکا۔ پھر کوشش کریں۔"</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"سوئچ نہیں کر سکتے۔ دوبارہ کوشش کرنے کے لیے تھپتھپائیں۔"</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"نئے آلہ کا جوڑا بنائیں"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"بلڈ نمبر"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"بلڈ نمبر کلپ بورڈ میں کاپی ہو گیا۔"</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"سبھی دیکھیں"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"نیٹ ورکس پر سوئچ کرنے کیلئے، ایتھرنیٹ غیر منسلک کریں"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"‏آلے کے تجربے کو بہتر بنانے کے لیے، Wi‑Fi کے آف ہونے پر بھی ایپس اور سروسز کسی بھی وقت Wi‑Fi نیٹ ورکس اسکین کر سکتی ہیں۔ آپ اسے Wi‑Fi اسکیننگ کی ترتیبات میں تبدیل کر سکتے ہیں۔ "<annotation id="link">"تبدیل کریں"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"ہوائی جہاز وضع آف کریں"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"صارف منتخب کریں"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"ایپس پس منظر میں چل رہی ہیں"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"روکیں"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ur/tiles_states_strings.xml b/packages/SystemUI/res/values-ur/tiles_states_strings.xml
index 217d445..3284fc5 100644
--- a/packages/SystemUI/res/values-ur/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ur/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"آف"</item>
     <item msgid="460891964396502657">"آن"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"غیر دستیاب"</item>
+    <item msgid="5581384648880018330">"آف"</item>
+    <item msgid="8000850843692192257">"آن"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 8ef5264..277f1c3 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Qurilmalar topilmadi"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi-Fi tarmoqqa ulanmagan"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Yorqinlik"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Teskari ranglar"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Ranglarni akslantirish"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"Boshqa sozlamalar"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Foydalanuvchi sozlamalari"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"Tayyor"</string>
@@ -747,7 +747,7 @@
     <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Ekranni toʻliq kattalashtirish"</string>
     <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Ekran qismini kattalashtirish"</string>
     <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Almashtirish"</string>
-    <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Maxsus imkoniyatlar tugmasi maxsus imkoniyatlar ishorasini almashtirdi\n\n"<annotation id="link">"Sozlamalarni ochish"</annotation></string>
+    <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Maxsus imkoniyatlarni ochish uchun bosing Sozlamalardan moslay yoki almashtira olasiz.\n\n"<annotation id="link">"Sozlamalar"</annotation></string>
     <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Vaqtinchalik berkitish uchun tugmani qirra tomon suring"</string>
     <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Yuqori chapga surish"</string>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Yuqori oʻngga surish"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Sozlamalar"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g> ilovasida ijro etilmoqda: <xliff:g id="SONG_NAME">%1$s</xliff:g> – <xliff:g id="ARTIST_NAME">%2$s</xliff:g>"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> / <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"Ijro"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"Pauza"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"Avvalgi trek"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"Keyingi trek"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Ijro"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> ilovasini ochish"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="APP_LABEL">%3$s</xliff:g> ilovasida ijro etish: <xliff:g id="SONG_NAME">%1$s</xliff:g> – <xliff:g id="ARTIST_NAME">%2$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="APP_LABEL">%2$s</xliff:g> ilovasida ijro etilmoqda: <xliff:g id="SONG_NAME">%1$s</xliff:g>"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"Qaytarish"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"<xliff:g id="DEVICENAME">%1$s</xliff:g>da ijro etish uchun yaqinroq keling"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"<xliff:g id="DEVICENAME">%1$s</xliff:g> qurilmasida ijro qilinmoqda"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Nofaol. Ilovani tekshiring"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Topilmadi"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Boshqarish imkonsiz"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 ta qurilma tanlandi"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> ta qurilma tanlandi"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(uzildi)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Ulanmadi. Qayta urining."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Xatolik. Qayta urinish uchun bosing."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Yangi qurilmani ulash"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Nashr raqami"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Nashr raqami vaqtinchalik xotiraga nusxalandi."</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"Hammasi"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Boshqa tarmoqqa almashish uchun Ethernet tarmogʻini uzing"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Qurilma ishlashini yaxshilash uchun ilova va xizmatlar hatto Wi-Fi yoqilmaganda ham istalgan vaqt Wi-Fi tarmoqlarni qidirishi mumkin. Buni taqiqlash uchun Wi-Fi tarmoqlarni qidirish funksiyasini faolsizlantiring. "<annotation id="link">"Sozlamalarni ochish"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Parvoz rejimini faolsizlantirish"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Foydalanuvchini tanlang"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Orqa fonda ishlayotgan ilovalar"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Stop"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-uz/tiles_states_strings.xml b/packages/SystemUI/res/values-uz/tiles_states_strings.xml
index 0fd077c..47bcf4d 100644
--- a/packages/SystemUI/res/values-uz/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-uz/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"Oʻchiq"</item>
     <item msgid="460891964396502657">"Yoniq"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"Bandman"</item>
+    <item msgid="5581384648880018330">"Oʻchiq"</item>
+    <item msgid="8000850843692192257">"Yoniq"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 245defb..1c1557e 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Không có thiết bị nào"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Chưa kết nối với Wi-Fi"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Độ sáng"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Đảo ngược màu"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Đảo màu"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"Chế độ cài đặt khác"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Cài đặt người dùng"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"Xong"</string>
@@ -747,7 +747,7 @@
     <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Phóng to toàn màn hình"</string>
     <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Phóng to một phần màn hình"</string>
     <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Chuyển"</string>
-    <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Nút hỗ trợ tiếp cận đã thay thế cử chỉ hỗ trợ tiếp cận\n\n"<annotation id="link">"Xem chế độ cài đặt"</annotation></string>
+    <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Nhấn để mở bộ tính năng hỗ trợ tiếp cận. Tuỳ chỉnh/thay thế nút này trong phần Cài đặt.\n\n"<annotation id="link">"Xem chế độ cài đặt"</annotation></string>
     <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Di chuyển nút sang cạnh để ẩn nút tạm thời"</string>
     <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Chuyển lên trên cùng bên trái"</string>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Chuyển lên trên cùng bên phải"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Cài đặt"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"Đang phát <xliff:g id="SONG_NAME">%1$s</xliff:g> của <xliff:g id="ARTIST_NAME">%2$s</xliff:g> trên <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g>/<xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"Phát"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"Tạm dừng"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"Bản nhạc trước"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"Bản nhạc tiếp theo"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Phát"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Mở <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Phát <xliff:g id="SONG_NAME">%1$s</xliff:g> của <xliff:g id="ARTIST_NAME">%2$s</xliff:g> trên <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Phát <xliff:g id="SONG_NAME">%1$s</xliff:g> trên <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"Hủy"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Đưa thiết bị đến gần hơn để phát trên <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"Đang phát trên <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Không hoạt động, hãy kiểm tra ứng dụng"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Không tìm thấy"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Không có chức năng điều khiển"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"Đã chọn 1 thiết bị"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"Đã chọn <xliff:g id="COUNT">%1$d</xliff:g> thiết bị"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(đã ngắt kết nối)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Không thể kết nối. Hãy thử lại."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Không thể chuyển đổi. Hãy nhấn để thử lại."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Ghép nối thiết bị mới"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Số bản dựng"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Đã sao chép số bản dựng vào bảng nhớ tạm."</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"Xem tất cả"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Để chuyển mạng, hãy rút cáp Ethernet"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Để cải thiện trải nghiệm khi dùng thiết bị, các ứng dụng và dịch vụ vẫn có thể quét tìm mạng Wi‑Fi bất cứ lúc nào, ngay cả khi Wi‑Fi tắt. Bạn có thể thay đổi chế độ này trong phần cài đặt tính năng Quét tìm Wi‑Fi. "<annotation id="link">"Thay đổi"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Tắt chế độ trên máy bay"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Chọn người dùng"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Các ứng dụng chạy trong nền"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Dừng"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-vi/tiles_states_strings.xml b/packages/SystemUI/res/values-vi/tiles_states_strings.xml
index 72ffc6d..ecc3223 100644
--- a/packages/SystemUI/res/values-vi/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-vi/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"Đang tắt"</item>
     <item msgid="460891964396502657">"Đang bật"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"Không hoạt động"</item>
+    <item msgid="5581384648880018330">"Đang tắt"</item>
+    <item msgid="8000850843692192257">"Đang bật"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 2e9ba10..efd24bc 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"没有可用设备"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"未连接到 WLAN 网络"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"亮度"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"反色"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"颜色反转"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"更多设置"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"用户设置"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"完成"</string>
@@ -747,7 +747,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="5217151214439341902">"点按即可打开无障碍功能。您可在“设置”中自定义或更换此按钮。\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>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"移至右上角"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"设置"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"正在通过<xliff:g id="APP_LABEL">%3$s</xliff:g>播放<xliff:g id="ARTIST_NAME">%2$s</xliff:g>的《<xliff:g id="SONG_NAME">%1$s</xliff:g>》"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> / <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"播放"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"暂停"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"上一首"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"下一首"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"播放"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"打开<xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"通过<xliff:g id="APP_LABEL">%3$s</xliff:g>播放<xliff:g id="ARTIST_NAME">%2$s</xliff:g>的《<xliff:g id="SONG_NAME">%1$s</xliff:g>》"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"通过<xliff:g id="APP_LABEL">%2$s</xliff:g>播放《<xliff:g id="SONG_NAME">%1$s</xliff:g>》"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"撤消"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"移近一点以在“<xliff:g id="DEVICENAME">%1$s</xliff:g>”上播放"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"正在“<xliff:g id="DEVICENAME">%1$s</xliff:g>”上播放"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"无效,请检查应用"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"未找到"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"控件不可用"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"已选择 1 个设备"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"已选择 <xliff:g id="COUNT">%1$d</xliff:g> 个设备"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(已断开连接)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"无法连接。请重试。"</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"无法切换。点按即可重试。"</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"与新设备配对"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"版本号"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"已将版本号复制到剪贴板。"</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"查看全部"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"如要切换网络,请断开以太网连接"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"为了提升设备的使用体验,即使 WLAN 已关闭,应用和服务仍可以随时扫描 WLAN 网络。您可以在 WLAN 扫描设置中更改此设置。"<annotation id="link">"更改"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"关闭飞行模式"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"选择用户"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"正在在后台运行的应用"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"停止"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/tiles_states_strings.xml b/packages/SystemUI/res/values-zh-rCN/tiles_states_strings.xml
index 7912813..43de98e 100644
--- a/packages/SystemUI/res/values-zh-rCN/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/tiles_states_strings.xml
@@ -153,8 +153,8 @@
   </string-array>
   <string-array name="tile_states_qr_code_scanner">
     <item msgid="7435143266149257618">"不可用"</item>
-    <item msgid="3301403109049256043">"关闭"</item>
-    <item msgid="8878684975184010135">"开启"</item>
+    <item msgid="3301403109049256043">"已关闭"</item>
+    <item msgid="8878684975184010135">"已开启"</item>
   </string-array>
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"不可用"</item>
@@ -163,7 +163,12 @@
   </string-array>
   <string-array name="tile_states_onehanded">
     <item msgid="8189342855739930015">"不可用"</item>
-    <item msgid="146088982397753810">"关闭"</item>
-    <item msgid="460891964396502657">"开启"</item>
+    <item msgid="146088982397753810">"已关闭"</item>
+    <item msgid="460891964396502657">"已开启"</item>
+  </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"不可用"</item>
+    <item msgid="5581384648880018330">"已关闭"</item>
+    <item msgid="8000850843692192257">"已开启"</item>
   </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 7550a73..e7cb583 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"沒有可用裝置"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"未連線至 Wi-Fi"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"亮度"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"反轉顏色"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"色彩反轉"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"更多設定"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"使用者設定"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"完成"</string>
@@ -747,7 +747,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="5217151214439341902">"㩒一下就可以開無障礙功能。喺「設定」度自訂或者取代呢個按鈕。\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>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"移去右上方"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"設定"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"正在透過 <xliff:g id="APP_LABEL">%3$s</xliff:g> 播放 <xliff:g id="ARTIST_NAME">%2$s</xliff:g> 的《<xliff:g id="SONG_NAME">%1$s</xliff:g>》"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g>/<xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"播放"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"暫停"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"上一首曲目"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"下一首曲目"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"播放"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"開啟 <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"在 <xliff:g id="APP_LABEL">%3$s</xliff:g> 播放 <xliff:g id="ARTIST_NAME">%2$s</xliff:g> 的《<xliff:g id="SONG_NAME">%1$s</xliff:g>》"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"在 <xliff:g id="APP_LABEL">%2$s</xliff:g> 播放《<xliff:g id="SONG_NAME">%1$s</xliff:g>》"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"復原"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"移近一點以在 <xliff:g id="DEVICENAME">%1$s</xliff:g> 上播放"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"正在 <xliff:g id="DEVICENAME">%1$s</xliff:g> 上播放"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"已停用,請檢查應用程式"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"找不到"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"無法使用控制功能"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"已選取 1 部裝置"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"已選取 <xliff:g id="COUNT">%1$d</xliff:g> 部裝置"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(已中斷連線)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"無法連線,請再試一次。"</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"無法切換,輕按即可重試。"</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"配對新裝置"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"版本號碼"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"版本號碼已複製到剪貼簿。"</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"顯示全部"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"如要切換網絡,請中斷以太網連線"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"為改善裝置的使用體驗,應用程式和服務仍可隨時掃瞄 Wi-Fi 網絡 (即使 Wi-Fi 已關閉)。您可在 Wi-Fi 掃瞄設定中變更此設定。"<annotation id="link">"變更"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"關閉飛行模式"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"選取使用者"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"正在背景中執行的應用程式"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"停止"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/tiles_states_strings.xml b/packages/SystemUI/res/values-zh-rHK/tiles_states_strings.xml
index 5f1b350..637fb4c 100644
--- a/packages/SystemUI/res/values-zh-rHK/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"關閉"</item>
     <item msgid="460891964396502657">"開啟"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"無法使用"</item>
+    <item msgid="5581384648880018330">"關閉"</item>
+    <item msgid="8000850843692192257">"開啟"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index a771098..11e4ac6 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"沒有可用裝置"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"未連線至 Wi-Fi"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"亮度"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"反轉顏色"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"色彩反轉"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"更多設定"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"使用者設定"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"完成"</string>
@@ -747,7 +747,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="5217151214439341902">"輕觸即可開啟無障礙功能。你可以前往「設定」自訂或更換這個按鈕。\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>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"移到右上方"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"設定"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"系統正透過「<xliff:g id="APP_LABEL">%3$s</xliff:g>」播放<xliff:g id="ARTIST_NAME">%2$s</xliff:g>的〈<xliff:g id="SONG_NAME">%1$s</xliff:g>〉"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g>,共 <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"播放"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"暫停"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"上一首"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"下一首"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"播放"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"開啟「<xliff:g id="APP_LABEL">%1$s</xliff:g>」"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"透過「<xliff:g id="APP_LABEL">%3$s</xliff:g>」播放<xliff:g id="ARTIST_NAME">%2$s</xliff:g>的〈<xliff:g id="SONG_NAME">%1$s</xliff:g>〉"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"透過「<xliff:g id="APP_LABEL">%2$s</xliff:g>」播放〈<xliff:g id="SONG_NAME">%1$s</xliff:g>〉"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"復原"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"如要在「<xliff:g id="DEVICENAME">%1$s</xliff:g>」上播放,請靠近這部裝置"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"正在「<xliff:g id="DEVICENAME">%1$s</xliff:g>」上播放"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"無效,請查看應用程式"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"找不到控制項"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"無法使用控制項"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"已選取 1 部裝置"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"已選取 <xliff:g id="COUNT">%1$d</xliff:g> 部裝置"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(連線中斷)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"無法連線,請再試一次。"</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"無法切換,輕觸即可重試。"</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"配對新裝置"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"版本號碼"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"已將版本號碼複製到剪貼簿。"</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"查看全部"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"如要切換網路,請中斷乙太網路連線"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"為提升裝置的使用體驗,應用程式和服務仍可隨時掃描 Wi‑Fi 網路,即使 Wi-Fi 連線功能處於關閉狀態時亦然。你可以前往「掃描 Wi-Fi」設定進行變更。"<annotation id="link">"變更"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"關閉飛航模式"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"選取使用者"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"目前在背景執行的應用程式"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"停止"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/tiles_states_strings.xml b/packages/SystemUI/res/values-zh-rTW/tiles_states_strings.xml
index 3d81fc8..266cf5d 100644
--- a/packages/SystemUI/res/values-zh-rTW/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"已關閉"</item>
     <item msgid="460891964396502657">"已開啟"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"無法使用"</item>
+    <item msgid="5581384648880018330">"已關閉"</item>
+    <item msgid="8000850843692192257">"已開啟"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 64920b2..8c7f030 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -250,7 +250,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Ayikho idivayisi etholakalayo"</string>
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"I-Wi-Fi ayixhunyiwe"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Ukugqama"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Faka imibala"</string>
+    <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Ukuguqulwa kombala"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"Izilungiselelo eziningi"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Amasethingi womsebenzisi"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"Kwenziwe"</string>
@@ -747,7 +747,7 @@
     <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Khulisa isikrini esigcwele"</string>
     <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Khulisa ingxenye eyesikrini"</string>
     <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Iswishi"</string>
-    <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Inkinobho yokufinyeleleka ishintshaniswe ngokuthinta kokufinyeleleka\n\n"<annotation id="link">"Buka amasethingi"</annotation></string>
+    <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Thepha ukuze uvule izakhi zokufinyelela. Enza ngendlela oyifisayo noma shintsha le nkinobho Kumasethingi.\n\n"<annotation id="link">"Buka amasethingi"</annotation></string>
     <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Hambisa inkinobho onqenqemeni ukuze uyifihle okwesikhashana"</string>
     <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Hamba phezulu kwesokunxele"</string>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Hamba phezulu ngakwesokudla"</string>
@@ -798,10 +798,17 @@
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Izilungiselelo"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"I-<xliff:g id="SONG_NAME">%1$s</xliff:g> ka-<xliff:g id="ARTIST_NAME">%2$s</xliff:g> idlala kusuka ku-<xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> ku-<xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+    <string name="controls_media_button_play" msgid="2705068099607410633">"Dlala"</string>
+    <string name="controls_media_button_pause" msgid="8614887780950376258">"Misa"</string>
+    <string name="controls_media_button_prev" msgid="8126822360056482970">"Ithrekhi yangaphambilini"</string>
+    <string name="controls_media_button_next" msgid="6662636627525947610">"Ithrekhi elandelayo"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Dlala"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Vula i-<xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Dlala i-<xliff:g id="SONG_NAME">%1$s</xliff:g> ka-<xliff:g id="ARTIST_NAME">%2$s</xliff:g> kusuka ku-<xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Dlala i-<xliff:g id="SONG_NAME">%1$s</xliff:g> kusuka ku-<xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+    <string name="media_transfer_undo" msgid="1895606387620728736">"Hlehlisa"</string>
+    <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Sondeza eduze ukudlala ku-<xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+    <string name="media_transfer_playing" msgid="3760048096352107789">"Idlala ku-<xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Akusebenzi, hlola uhlelo lokusebenza"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Ayitholakali"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Ukulawula akutholakali"</string>
@@ -816,7 +823,7 @@
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"idivayisi ekhethiwe e-1"</string>
     <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"amadivayisi akhethiwe angu-<xliff:g id="COUNT">%1$d</xliff:g>"</string>
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(inqamukile)"</string>
-    <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Ayikwazanga ukuxhumeka. Zama futhi."</string>
+    <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Akukwazi ukushintsha. Thepha ukuze uzame futhi."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Bhangqa idivayisi entsha"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Yakha inombolo"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Yakha inombolo ekopishelwe kubhodi yokunamathisela."</string>
@@ -881,8 +888,11 @@
     <string name="see_all_networks" msgid="3773666844913168122">"Bona konke"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Ukuze ushintshe amanethiwekhi, nqamula i-ethernet"</string>
     <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Ukuze kuthuthukiswe ukuzizwela kwedivayisi, ama-app namasevisi kusengakwazi ukuskena amanethiwekhi we-Wi-Fi noma kunini, ngisho noma i-Wi-Fi ivaliwe, Ungashintsha lokhu kumasethingi Wokuskena i-Wi-Fi. "<annotation id="link">"Shintsha"</annotation></string>
+    <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Vala imodi yendiza"</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>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Khetha umsebenzisi"</string>
+    <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Ama-app ayaqhubeka ngemuva"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Misa"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zu/tiles_states_strings.xml b/packages/SystemUI/res/values-zu/tiles_states_strings.xml
index a124c9e..9cac4ae 100644
--- a/packages/SystemUI/res/values-zu/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-zu/tiles_states_strings.xml
@@ -166,4 +166,9 @@
     <item msgid="146088982397753810">"Valiwe"</item>
     <item msgid="460891964396502657">"Vuliwe"</item>
   </string-array>
+  <string-array name="tile_states_fgsmanager">
+    <item msgid="3054341646818213094">"Akutholakali"</item>
+    <item msgid="5581384648880018330">"Valiwe"</item>
+    <item msgid="8000850843692192257">"Vuliwe"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 3695286..7b8f349 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -82,7 +82,7 @@
 
     <!-- Tiles native to System UI. Order should match "quick_settings_tiles_default" -->
     <string name="quick_settings_tiles_stock" translatable="false">
-        internet,bt,flashlight,dnd,alarm,airplane,controls,wallet,rotation,battery,cast,screenrecord,mictoggle,cameratoggle,location,hotspot,inversion,saver,dark,work,night,reverse,reduce_brightness,qr_code_scanner,onehanded,fgsmanager
+        internet,bt,flashlight,dnd,alarm,airplane,controls,wallet,rotation,battery,cast,screenrecord,mictoggle,cameratoggle,location,hotspot,inversion,saver,dark,work,night,reverse,reduce_brightness,qr_code_scanner,onehanded,fgsmanager,color_correction
     </string>
 
     <!-- The tiles to display in QuickSettings -->
@@ -97,6 +97,7 @@
          The syntax is setting-name:spec. If the tile is a TileService, the spec should be specified
          as custom(package/class). Relative class name is supported. -->
     <string-array name="config_quickSettingsAutoAdd" translatable="false">
+        <item>accessibility_display_daltonizer_enabled:color_correction</item>
         <item>accessibility_display_inversion_enabled:inversion</item>
         <item>one_handed_mode_enabled:onehanded</item>
     </string-array>
@@ -714,19 +715,19 @@
     <bool name="config_enablePrivacyDot">true</bool>
 
     <!-- The positions widgets can be in defined as View.Gravity constants -->
-    <integer-array name="config_dreamOverlayPositions">
+    <integer-array name="config_dreamComplicationPositions">
     </integer-array>
 
-    <!-- Widget components to show as dream overlays -->
-    <string-array name="config_dreamOverlayComponents" translatable="false">
+    <!-- Widget components to show as dream complications -->
+    <string-array name="config_dreamAppWidgetComplications" translatable="false">
     </string-array>
 
-    <!-- Width percentage of dream overlay components -->
-    <item name="config_dreamOverlayComponentWidthPercent" translatable="false" format="float"
+    <!-- Width percentage of dream complications -->
+    <item name="config_dreamComplicationWidthPercent" translatable="false" format="float"
           type="dimen">0.33</item>
 
-    <!-- Height percentage of dream overlay components -->
-    <item name="config_dreamOverlayComponentHeightPercent" translatable="false" format="float"
+    <!-- Height percentage of dream complications -->
+    <item name="config_dreamComplicationHeightPercent" translatable="false" format="float"
           type="dimen">0.25</item>
 
     <!-- Flag to enable dream overlay service and its registration -->
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 843c69f..b12db5d 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -969,6 +969,10 @@
     <dimen name="qs_media_enabled_seekbar_vertical_padding">28dp</dimen>
     <dimen name="qs_media_disabled_seekbar_vertical_padding">29dp</dimen>
 
+    <!-- Sizes for alternate session-based layout -->
+    <dimen name="qs_media_session_enabled_seekbar_vertical_padding">15dp</dimen>
+    <dimen name="qs_media_session_disabled_seekbar_vertical_padding">16dp</dimen>
+
     <!-- Size of Smartspace media recommendations cards in the QSPanel carousel -->
     <dimen name="qs_aa_media_rec_album_size_collapsed">72dp</dimen>
     <dimen name="qs_aa_media_rec_album_size_expanded">76dp</dimen>
@@ -977,13 +981,18 @@
     <dimen name="qs_aa_media_rec_album_margin_vert">4dp</dimen>
     <dimen name="qq_aa_media_rec_header_text_size">16sp</dimen>
 
-    <!-- Media tap-to-transfer chip -->
+    <!-- Media tap-to-transfer chip for sender device -->
     <dimen name="media_ttt_chip_outer_padding">16dp</dimen>
     <dimen name="media_ttt_text_size">16sp</dimen>
-    <dimen name="media_ttt_icon_size">16dp</dimen>
+    <dimen name="media_ttt_icon_size">24dp</dimen>
+    <dimen name="media_ttt_loading_size">20dp</dimen>
     <dimen name="media_ttt_undo_button_vertical_padding">8dp</dimen>
     <dimen name="media_ttt_undo_button_vertical_negative_margin">-8dp</dimen>
 
+    <!-- Media tap-to-transfer chip for receiver device -->
+    <dimen name="media_ttt_chip_size_receiver">100dp</dimen>
+    <dimen name="media_ttt_icon_size_receiver">95dp</dimen>
+
     <!-- Window magnification -->
     <dimen name="magnification_border_drag_size">35dp</dimen>
     <dimen name="magnification_outer_border_margin">15dp</dimen>
@@ -1259,6 +1268,8 @@
 
     <!-- Internet dialog related dimensions -->
     <dimen name="internet_dialog_corner_radius">24dp</dimen>
+    <!-- Width of progress bar -->
+    <dimen name="internet_dialog_progress_bar_width">152dp</dimen>
     <!-- End margin of network layout -->
     <dimen name="internet_dialog_network_layout_margin">16dp</dimen>
     <!-- Size of switch bar in internet dialog -->
@@ -1308,4 +1319,7 @@
     <dimen name="dream_overlay_status_bar_height">80dp</dimen>
     <dimen name="dream_overlay_status_bar_margin">40dp</dimen>
     <dimen name="dream_overlay_status_icon_margin">8dp</dimen>
+    <!-- Height of the area at the top of the dream overlay to allow dragging down the notifications
+         shade. -->
+    <dimen name="dream_overlay_notifications_drag_area_height">100dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 99508a5..2bf121d2e 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -425,64 +425,24 @@
     <!-- Content description for the close button in the zen mode panel introduction message. [CHAR LIMIT=NONE] -->
     <string name="accessibility_desc_close">Close</string>
 
-    <!-- Announcement made when the wifi is turned off (not shown on the screen). [CHAR LIMIT=NONE] -->
-    <string name="accessibility_quick_settings_wifi_changed_off">Wifi turned off.</string>
-    <!-- Announcement made when the wifi is turned on (not shown on the screen). [CHAR LIMIT=NONE] -->
-    <string name="accessibility_quick_settings_wifi_changed_on">Wifi turned on.</string>
-    <!-- Announcement made when the airplane mode changes to off (not shown on the screen). [CHAR LIMIT=NONE] -->
-    <string name="accessibility_quick_settings_airplane_changed_off">Airplane mode turned off.</string>
-    <!-- Announcement made when the airplane mode changes to on (not shown on the screen). [CHAR LIMIT=NONE] -->
-    <string name="accessibility_quick_settings_airplane_changed_on">Airplane mode turned on.</string>
     <!-- Content description of the do not disturb tile in quick settings when on in none (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_quick_settings_dnd_none_on">total silence</string>
     <!-- Content description of the do not disturb tile in quick settings when on in alarms only (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_quick_settings_dnd_alarms_on">alarms only</string>
      <!-- Content description of the do not disturb tile in quick settings (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_quick_settings_dnd">Do Not Disturb.</string>
-    <!-- Announcement made when do not disturb changes to off (not shown on the screen). [CHAR LIMIT=NONE] -->
-    <string name="accessibility_quick_settings_dnd_changed_off">Do Not Disturb turned off.</string>
-    <!-- Announcement made when do not disturb changes to on (not shown on the screen). [CHAR LIMIT=NONE] -->
-    <string name="accessibility_quick_settings_dnd_changed_on">Do Not Disturb turned on.</string>
     <!-- Content description of the bluetooth tile in quick settings (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_quick_settings_bluetooth">Bluetooth.</string>
     <!-- Content description of the bluetooth tile in quick settings when on (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_quick_settings_bluetooth_on">Bluetooth on.</string>
-    <!-- Announcement made when the bluetooth is turned off (not shown on the screen). [CHAR LIMIT=NONE] -->
-    <string name="accessibility_quick_settings_bluetooth_changed_off">Bluetooth turned off.</string>
-    <!-- Announcement made when the bluetooth is turned on (not shown on the screen). [CHAR LIMIT=NONE] -->
-    <string name="accessibility_quick_settings_bluetooth_changed_on">Bluetooth turned on.</string>
-    <!-- Announcement made when the location tile changes to off (not shown on the screen). [CHAR LIMIT=NONE] -->
-    <string name="accessibility_quick_settings_location_changed_off">Location reporting turned off.</string>
-    <!-- Announcement made when the location tile changes to on (not shown on the screen). [CHAR LIMIT=NONE] -->
-    <string name="accessibility_quick_settings_location_changed_on">Location reporting turned on.</string>
     <!-- Content description of the alarm tile in quick settings (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_quick_settings_alarm">Alarm set for <xliff:g id="time" example="Wed 3:30 PM">%s</xliff:g>.</string>
     <!-- Content description of zen mode time condition plus button (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_quick_settings_more_time">More time.</string>
     <!-- Content description of zen mode time condition minus button (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_quick_settings_less_time">Less time.</string>
-    <!-- Announcement made when the flashlight state changes to off (not shown on the screen). [CHAR LIMIT=NONE] -->
-    <string name="accessibility_quick_settings_flashlight_changed_off">Flashlight turned off.</string>
-    <!-- Announcement made when the flashlight state changes to on (not shown on the screen). [CHAR LIMIT=NONE] -->
-    <string name="accessibility_quick_settings_flashlight_changed_on">Flashlight turned on.</string>
-    <!-- Announcement made when the color inversion state changes to off (not shown on the screen). [CHAR LIMIT=NONE] -->
-    <string name="accessibility_quick_settings_color_inversion_changed_off">Color inversion turned off.</string>
-    <!-- Announcement made when the color inversion state changes to on (not shown on the screen). [CHAR LIMIT=NONE] -->
-    <string name="accessibility_quick_settings_color_inversion_changed_on">Color inversion turned on.</string>
-    <!-- Announcement made when the hotspot state changes to off (not shown on the screen). [CHAR LIMIT=NONE] -->
-    <string name="accessibility_quick_settings_hotspot_changed_off">Mobile hotspot turned off.</string>
-    <!-- Announcement made when the hotspot state changes to on (not shown on the screen). [CHAR LIMIT=NONE] -->
-    <string name="accessibility_quick_settings_hotspot_changed_on">Mobile hotspot turned on.</string>
     <!-- Announcement made when the screen stopped casting (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_casting_turned_off">Screen casting stopped.</string>
-    <!-- Announcement made when the work mode changes to off (not shown on the screen). Paused is used as a verb. [CHAR LIMIT=NONE] -->
-    <!-- Announcement made when the work mode changes to on (not shown on the screen). [CHAR LIMIT=NONE] -->
-    <!-- Announcement made when the Data Saver changes to off (not shown on the screen). [CHAR LIMIT=NONE] -->
-    <string name="accessibility_quick_settings_data_saver_changed_off">Data Saver turned off.</string>
-    <!-- Announcement made when the Data Saver changes to on (not shown on the screen). [CHAR LIMIT=NONE] -->
-    <string name="accessibility_quick_settings_data_saver_changed_on">Data Saver turned on.</string>
-    <!-- Announcement made when the Sensor Privacy changes to off (not shown on the screen). [CHAR LIMIT=NONE] -->
-    <!-- Announcement made when the Sensor Privacy changes to on (not shown on the screen). [CHAR LIMIT=NONE] -->
 
     <!-- Content description of the display brightness slider (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_brightness">Display brightness</string>
@@ -636,6 +596,7 @@
     <!-- QuickSettings: Label for the toggle that controls whether display inversion is enabled. [CHAR LIMIT=NONE] -->
     <string name="quick_settings_inversion_label">Color inversion</string>
     <!-- QuickSettings: Label for the toggle that controls whether display color correction is enabled. [CHAR LIMIT=NONE] -->
+    <string name="quick_settings_color_correction_label">Color correction</string>
     <!-- QuickSettings: Control panel: Label for button that navigates to settings. [CHAR LIMIT=NONE] -->
     <string name="quick_settings_more_settings">More settings</string>
     <!-- QuickSettings: Control panel: Label for button that navigates to user settings. [CHAR LIMIT=NONE] -->
@@ -1277,6 +1238,10 @@
 
     <!-- [CHAR LIMIT=NONE] Importance Tuner setting title -->
     <string name="tuner_full_importance_settings">Power notification controls</string>
+
+    <!-- [CHAR LIMIT=NONE] Notification camera based rotation enabled description -->
+    <string name="rotation_lock_camera_rotation_on">On - Face-based</string>
+
     <string name="power_notification_controls_description">With power notification controls, you can set an importance level from 0 to 5 for an app\'s notifications.
         \n\n<b>Level 5</b>
         \n- Show at the top of the notification list
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 9358349..18bfb52 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -581,6 +581,23 @@
         <item name="android:scaleType">centerInside</item>
     </style>
 
+    <style name="MediaPlayer.SessionAction"
+           parent="@android:style/Widget.Material.Button.Borderless.Small">
+        <item name="android:background">@drawable/qs_media_light_source</item>
+        <item name="android:tint">?android:attr/textColorPrimary</item>
+        <item name="android:stateListAnimator">@anim/media_button_state_list_animator</item>
+        <item name="android:paddingTop">12dp</item>
+        <item name="android:paddingStart">12dp</item>
+        <item name="android:paddingEnd">12dp</item>
+        <item name="android:paddingBottom">12dp</item>
+        <item name="android:scaleType">centerInside</item>
+    </style>
+
+    <style name="MediaPlayer.SessionAction.Primary" parent="MediaPlayer.SessionAction">
+        <item name="android:background">@drawable/qs_media_round_button_background</item>
+        <item name="android:backgroundTint">@color/media_player_solid_button_bg</item>
+    </style>
+
     <style name="MediaPlayer.OutlineButton">
         <item name="android:background">@drawable/qs_media_button_background</item>
         <item name="android:textColor">?android:attr/textColorPrimary</item>
diff --git a/packages/SystemUI/res/values/tiles_states_strings.xml b/packages/SystemUI/res/values/tiles_states_strings.xml
index 5fdb497..a610caa 100644
--- a/packages/SystemUI/res/values/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values/tiles_states_strings.xml
@@ -142,6 +142,16 @@
         <item>On</item>
     </string-array>
 
+    <!-- State names for color correction tile: unavailable, off, on.
+         This subtitle is shown when the tile is in that particular state but does not set its own
+         subtitle, so some of these may never appear on screen. They should still be translated as
+         if they could appear. [CHAR LIMIT=32] -->
+    <string-array name="tile_states_color_correction">
+        <item>Unavailable</item>
+        <item>Off</item>
+        <item>On</item>
+    </string-array>
+
     <!-- State names for (color) inversion tile: unavailable, off, on.
          This subtitle is shown when the tile is in that particular state but does not set its own
          subtitle, so some of these may never appear on screen. They should still be translated as
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 c1d9d0d..4ec65d8 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
@@ -282,7 +282,9 @@
      * @see SurfaceControl#release()
      */
     public void release() {
-        leash.mSurfaceControl.release();
+        if (leash.mSurfaceControl != null) {
+            leash.mSurfaceControl.release();
+        }
         if (mStartLeash != null) {
             mStartLeash.release();
         }
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 3cd090e..2d5080e 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
@@ -246,10 +246,6 @@
                 if (mPausingTasks.contains(openingTasks.get(i).getContainer())) {
                     ++pauseMatches;
                 }
-                if (openingTasks.get(i).getContainer().equals(mPausingTasks.get(i))) {
-                    // In this case, we are "returning" to an already running app, so just consume
-                    // the merge and do nothing.
-                }
             }
             if (pauseMatches > 0) {
                 if (pauseMatches != mPausingTasks.size()) {
@@ -275,9 +271,9 @@
                 t.reparent(target.leash.mSurfaceControl, mInfo.getRootLeash());
                 t.setLayer(target.leash.mSurfaceControl, layer);
                 t.hide(target.leash.mSurfaceControl);
-                t.apply();
                 targets[i] = target;
             }
+            t.apply();
             recents.onTasksAppeared(targets);
             return true;
         }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt
index ac946ca..24e93ef 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt
@@ -30,6 +30,7 @@
 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.util.ATraceLoggerTransitionProgressListener
 import java.lang.IllegalStateException
 import java.util.concurrent.Executor
 
@@ -46,7 +47,8 @@
     deviceStateManager: DeviceStateManager,
     sensorManager: SensorManager,
     mainHandler: Handler,
-    mainExecutor: Executor
+    mainExecutor: Executor,
+    tracingTagPrefix: String
 ): UnfoldTransitionProgressProvider {
 
     if (!config.isEnabled) {
@@ -76,9 +78,12 @@
         FixedTimingTransitionProgressProvider(foldStateProvider)
     }
     return ScaleAwareTransitionProgressProvider(
-            unfoldTransitionProgressProvider,
-            context.contentResolver
-    )
+        unfoldTransitionProgressProvider,
+        context.contentResolver
+    ).apply {
+        // Always present callback that logs animation beginning and end.
+        addCallback(ATraceLoggerTransitionProgressListener(tracingTagPrefix))
+    }
 }
 
 fun createConfig(context: Context): UnfoldTransitionConfig =
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt
index 51eae57..a701b44 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt
@@ -23,7 +23,7 @@
 import androidx.dynamicanimation.animation.SpringForce
 import com.android.systemui.unfold.UnfoldTransitionProgressProvider
 import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
-import com.android.systemui.unfold.updates.FOLD_UPDATE_ABORTED
+import com.android.systemui.unfold.updates.FOLD_UPDATE_FINISH_HALF_OPEN
 import com.android.systemui.unfold.updates.FOLD_UPDATE_FINISH_CLOSED
 import com.android.systemui.unfold.updates.FOLD_UPDATE_START_CLOSING
 import com.android.systemui.unfold.updates.FOLD_UPDATE_FINISH_FULL_OPEN
@@ -32,12 +32,7 @@
 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 postures
- */
+/** Maps fold updates to unfold transition progress using DynamicAnimation. */
 internal class PhysicsBasedUnfoldTransitionProgressProvider(
     private val foldStateProvider: FoldStateProvider
 ) :
@@ -89,7 +84,7 @@
                     cancelTransition(endValue = 1f, animate = true)
                 }
             }
-            FOLD_UPDATE_FINISH_FULL_OPEN, FOLD_UPDATE_ABORTED -> {
+            FOLD_UPDATE_FINISH_FULL_OPEN, FOLD_UPDATE_FINISH_HALF_OPEN -> {
                 // Do not cancel if we haven't started the transition yet.
                 // This could happen when we fully unfolded the device before the screen
                 // became available. In this case we start and immediately cancel the animation
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
index 6d9631c..cd1ea21 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
@@ -138,7 +138,7 @@
         if (isTransitionInProgess) {
             cancelTimeout()
         }
-        handler.postDelayed(timeoutRunnable, ABORT_CLOSING_MILLIS)
+        handler.postDelayed(timeoutRunnable, HALF_OPENED_TIMEOUT_MILLIS)
     }
 
     private fun cancelTimeout() {
@@ -163,16 +163,14 @@
     }
 
     private inner class HingeAngleListener : Consumer<Float> {
-
         override fun accept(angle: Float) {
             onHingeAngle(angle)
         }
     }
 
     private inner class TimeoutRunnable : Runnable {
-
         override fun run() {
-            notifyFoldUpdate(FOLD_UPDATE_ABORTED)
+            notifyFoldUpdate(FOLD_UPDATE_FINISH_HALF_OPEN)
         }
     }
 }
@@ -180,9 +178,7 @@
 private fun stateToString(@FoldUpdate update: Int): String {
     return when (update) {
         FOLD_UPDATE_START_OPENING -> "START_OPENING"
-        FOLD_UPDATE_HALF_OPEN -> "HALF_OPEN"
         FOLD_UPDATE_START_CLOSING -> "START_CLOSING"
-        FOLD_UPDATE_ABORTED -> "ABORTED"
         FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE -> "UNFOLDED_SCREEN_AVAILABLE"
         FOLD_UPDATE_FINISH_HALF_OPEN -> "FINISH_HALF_OPEN"
         FOLD_UPDATE_FINISH_FULL_OPEN -> "FINISH_FULL_OPEN"
@@ -195,11 +191,11 @@
 private const val DEBUG = false
 
 /**
- * Time after which [FOLD_UPDATE_ABORTED] is emitted following a [FOLD_UPDATE_START_CLOSING] or
- * [FOLD_UPDATE_START_OPENING] event, if an end state is not reached.
+ * Time after which [FOLD_UPDATE_FINISH_HALF_OPEN] is emitted following a
+ * [FOLD_UPDATE_START_CLOSING] or [FOLD_UPDATE_START_OPENING] event, if an end state is not reached.
  */
 @VisibleForTesting
-const val ABORT_CLOSING_MILLIS = 1000L
+const val HALF_OPENED_TIMEOUT_MILLIS = 1000L
 
 /** Threshold after which we consider the device fully unfolded. */
 @VisibleForTesting
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/FoldStateProvider.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/FoldStateProvider.kt
index bffebcd..df3563d 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/FoldStateProvider.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/FoldStateProvider.kt
@@ -37,9 +37,7 @@
 
     @IntDef(prefix = ["FOLD_UPDATE_"], value = [
         FOLD_UPDATE_START_OPENING,
-        FOLD_UPDATE_HALF_OPEN,
         FOLD_UPDATE_START_CLOSING,
-        FOLD_UPDATE_ABORTED,
         FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE,
         FOLD_UPDATE_FINISH_HALF_OPEN,
         FOLD_UPDATE_FINISH_FULL_OPEN,
@@ -50,10 +48,8 @@
 }
 
 const val FOLD_UPDATE_START_OPENING = 0
-const val FOLD_UPDATE_HALF_OPEN = 1
-const val FOLD_UPDATE_START_CLOSING = 2
-const val FOLD_UPDATE_ABORTED = 3
-const val FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE = 4
-const val FOLD_UPDATE_FINISH_HALF_OPEN = 5
-const val FOLD_UPDATE_FINISH_FULL_OPEN = 6
-const val FOLD_UPDATE_FINISH_CLOSED = 7
+const val FOLD_UPDATE_START_CLOSING = 1
+const val FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE = 2
+const val FOLD_UPDATE_FINISH_HALF_OPEN = 3
+const val FOLD_UPDATE_FINISH_FULL_OPEN = 4
+const val FOLD_UPDATE_FINISH_CLOSED = 5
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/util/ATraceLoggerTransitionProgressProvider.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/util/ATraceLoggerTransitionProgressProvider.kt
new file mode 100644
index 0000000..f3eeb32
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/util/ATraceLoggerTransitionProgressProvider.kt
@@ -0,0 +1,29 @@
+package com.android.systemui.unfold.util
+
+import android.os.Trace
+import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
+
+/**
+ * Listener that logs start and end of the fold-unfold transition.
+ *
+ * [tracePrefix] arg helps in differentiating those. Currently, this is expected to be logged twice
+ * for each fold/unfold: in (1) systemui and (2) launcher process.
+ */
+class ATraceLoggerTransitionProgressListener(tracePrefix: String) : TransitionProgressListener {
+
+    private val traceName = "$tracePrefix#$UNFOLD_TRANSITION_TRACE_NAME"
+
+    override fun onTransitionStarted() {
+        Trace.beginAsyncSection(traceName, /* cookie= */ 0)
+    }
+
+    override fun onTransitionFinished() {
+        Trace.endAsyncSection(traceName, /* cookie= */ 0)
+    }
+
+    override fun onTransitionProgress(progress: Float) {
+        Trace.setCounter(traceName, (progress * 100).toLong())
+    }
+}
+
+private const val UNFOLD_TRANSITION_TRACE_NAME = "FoldUnfoldTransitionInProgress"
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardRootViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardRootViewController.java
deleted file mode 100644
index 4e375c2..0000000
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardRootViewController.java
+++ /dev/null
@@ -1,48 +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.keyguard;
-
-import android.view.ViewGroup;
-
-import com.android.keyguard.dagger.KeyguardBouncerScope;
-import com.android.systemui.dagger.qualifiers.RootView;
-import com.android.systemui.statusbar.phone.KeyguardBouncer;
-import com.android.systemui.util.ViewController;
-
-import javax.inject.Inject;
-/** Controller for a {@link KeyguardBouncer}'s Root view. */
-@KeyguardBouncerScope
-public class KeyguardRootViewController extends ViewController<ViewGroup> {
-    @Inject
-    public KeyguardRootViewController(@RootView ViewGroup view) {
-        super(view);
-    }
-
-    public ViewGroup getView() {
-        return mView;
-    }
-
-    @Override
-    protected void onViewAttached() {
-
-    }
-
-    @Override
-    protected void onViewDetached() {
-
-    }
-}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index b84cb19..b5ea498 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -32,9 +32,14 @@
 import android.app.AlertDialog;
 import android.content.Context;
 import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BlendMode;
 import android.graphics.Rect;
+import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.LayerDrawable;
+import android.os.UserManager;
 import android.provider.Settings;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -70,6 +75,7 @@
 import com.android.internal.util.UserIcons;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
+import com.android.settingslib.Utils;
 import com.android.systemui.Gefingerpoken;
 import com.android.systemui.R;
 import com.android.systemui.animation.Interpolators;
@@ -760,11 +766,11 @@
         private ViewGroup mView;
         private ViewGroup mUserSwitcherViewGroup;
         private KeyguardSecurityViewFlipper mViewFlipper;
-        private ImageView mUserIconView;
         private TextView mUserSwitcher;
         private FalsingManager mFalsingManager;
         private UserSwitcherController mUserSwitcherController;
         private KeyguardUserSwitcherPopupMenu mPopup;
+        private Resources mResources;
 
         @Override
         public void init(@NonNull ViewGroup v, @NonNull GlobalSettings globalSettings,
@@ -775,6 +781,7 @@
             mViewFlipper = viewFlipper;
             mFalsingManager = falsingManager;
             mUserSwitcherController = userSwitcherController;
+            mResources = v.getContext().getResources();
 
             if (mUserSwitcherViewGroup == null) {
                 LayoutInflater.from(v.getContext()).inflate(
@@ -784,9 +791,8 @@
                 mUserSwitcherViewGroup =  mView.findViewById(R.id.keyguard_bouncer_user_switcher);
             }
 
-            mUserIconView = mView.findViewById(R.id.user_icon);
-            Drawable icon = UserIcons.getDefaultUserIcon(v.getContext().getResources(), 0, false);
-            mUserIconView.setImageDrawable(icon);
+            Drawable userIcon = findUserIcon(KeyguardUpdateMonitor.getCurrentUser());
+            ((ImageView) mView.findViewById(R.id.user_icon)).setImageDrawable(userIcon);
 
             updateSecurityViewLocation();
 
@@ -802,6 +808,14 @@
             }
         }
 
+        private Drawable findUserIcon(int userId) {
+            Bitmap userIcon = UserManager.get(mView.getContext()).getUserIcon(userId);
+            if (userIcon != null) {
+                return new BitmapDrawable(userIcon);
+            }
+            return UserIcons.getDefaultUserIcon(mResources, userId, false);
+        }
+
         @Override
         public void startAppearAnimation(SecurityMode securityMode) {
             // IME insets animations handle alpha and translation
@@ -824,8 +838,7 @@
                 return;
             }
 
-            int yTranslation = mView.getContext().getResources().getDimensionPixelSize(
-                    R.dimen.disappear_y_translation);
+            int yTranslation = mResources.getDimensionPixelSize(R.dimen.disappear_y_translation);
 
             AnimatorSet anims = new AnimatorSet();
             ObjectAnimator yAnim = ObjectAnimator.ofFloat(mView, View.TRANSLATION_Y, yTranslation);
@@ -840,21 +853,70 @@
             String currentUserName = mUserSwitcherController.getCurrentUserName();
             mUserSwitcher.setText(currentUserName);
 
+            final UserRecord currentUser = getCurrentUser();
             ViewGroup anchor = mView.findViewById(R.id.user_switcher_anchor);
             BaseUserAdapter adapter = new BaseUserAdapter(mUserSwitcherController) {
                 @Override
                 public View getView(int position, View convertView, ViewGroup parent) {
                     UserRecord item = getItem(position);
-                    TextView view = (TextView) convertView;
+                    FrameLayout view = (FrameLayout) convertView;
                     if (view == null) {
-                        view = (TextView) LayoutInflater.from(parent.getContext()).inflate(
+                        view = (FrameLayout) LayoutInflater.from(parent.getContext()).inflate(
                                 R.layout.keyguard_bouncer_user_switcher_item,
                                 parent,
                                 false);
                     }
-                    view.setText(getName(parent.getContext(), item));
+                    TextView textView = (TextView) view.getChildAt(0);
+                    textView.setText(getName(parent.getContext(), item));
+                    Drawable icon = null;
+                    if (item.picture != null) {
+                        icon = new BitmapDrawable(item.picture);
+                    } else {
+                        icon = getDrawable(item, view.getContext());
+                    }
+                    int iconSize = view.getResources().getDimensionPixelSize(
+                            R.dimen.bouncer_user_switcher_item_icon_size);
+                    int iconPadding = view.getResources().getDimensionPixelSize(
+                            R.dimen.bouncer_user_switcher_item_icon_padding);
+                    icon.setBounds(0, 0, iconSize, iconSize);
+                    textView.setCompoundDrawablePadding(iconPadding);
+                    textView.setCompoundDrawablesRelative(icon, null, null, null);
+
+                    if (item == currentUser) {
+                        textView.setBackground(view.getContext().getDrawable(
+                                R.drawable.bouncer_user_switcher_item_selected_bg));
+                    } else {
+                        textView.setBackground(null);
+                    }
                     return view;
                 }
+
+                private Drawable getDrawable(UserRecord item, Context context) {
+                    Drawable drawable;
+                    if (item.isCurrent && item.isGuest) {
+                        drawable = context.getDrawable(R.drawable.ic_avatar_guest_user);
+                    } else {
+                        drawable = getIconDrawable(context, item);
+                    }
+
+                    int iconColor;
+                    if (item.isSwitchToEnabled) {
+                        iconColor = Utils.getColorAttrDefaultColor(context,
+                                com.android.internal.R.attr.colorAccentPrimaryVariant);
+                    } else {
+                        iconColor = context.getResources().getColor(
+                                R.color.kg_user_switcher_restricted_avatar_icon_color,
+                                context.getTheme());
+                    }
+                    drawable.setTint(iconColor);
+
+                    Drawable bg = context.getDrawable(R.drawable.kg_bg_avatar);
+                    bg.setTintBlendMode(BlendMode.DST);
+                    bg.setTint(Utils.getColorAttrDefaultColor(context,
+                                com.android.internal.R.attr.colorSurfaceVariant));
+                    drawable = new LayerDrawable(new Drawable[]{bg, drawable});
+                    return drawable;
+                }
             };
 
             if (adapter.getCount() < 2) {
@@ -876,7 +938,8 @@
                         public void onItemClick(AdapterView parent, View view, int pos, long id) {
                             if (mFalsingManager.isFalseTap(LOW_PENALTY)) return;
 
-                            UserRecord user = adapter.getItem(pos);
+                            // Subtract one for the header
+                            UserRecord user = adapter.getItem(pos - 1);
                             if (!user.isCurrent) {
                                 adapter.onUserListItemClicked(user);
                             }
@@ -888,6 +951,16 @@
             });
         }
 
+        private UserRecord getCurrentUser() {
+            for (int i = 0; i < mUserSwitcherController.getUsers().size(); ++i) {
+                UserRecord userRecord = mUserSwitcherController.getUsers().get(i);
+                if (userRecord.isCurrent) {
+                    return userRecord;
+                }
+            }
+            return null;
+        }
+
         /**
          * Each view will get half the width. Yes, it would be easier to use something other than
          * FrameLayout but it was too disruptive to downstream projects to change.
@@ -901,8 +974,7 @@
 
         @Override
         public void updateSecurityViewLocation() {
-            if (mView.getContext().getResources().getConfiguration().orientation
-                    == Configuration.ORIENTATION_PORTRAIT) {
+            if (mResources.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
                 updateViewGravity(mViewFlipper, Gravity.CENTER_HORIZONTAL);
                 updateViewGravity(mUserSwitcherViewGroup, Gravity.CENTER_HORIZONTAL);
                 mUserSwitcherViewGroup.setTranslationY(0);
@@ -912,8 +984,7 @@
 
                 // Attempt to reposition a bit higher to make up for this frame being a bit lower
                 // on the device
-                int yTrans = mView.getContext().getResources().getDimensionPixelSize(
-                        R.dimen.status_bar_height);
+                int yTrans = mResources.getDimensionPixelSize(R.dimen.status_bar_height);
                 mUserSwitcherViewGroup.setTranslationY(-yTrans);
             }
         }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 2789e27..98721fd 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -94,7 +94,6 @@
 import com.android.internal.widget.LockPatternUtils;
 import com.android.settingslib.WirelessUtils;
 import com.android.settingslib.fuelgauge.BatteryStatus;
-import com.android.systemui.DejankUtils;
 import com.android.systemui.Dumpable;
 import com.android.systemui.R;
 import com.android.systemui.biometrics.AuthController;
@@ -173,7 +172,6 @@
     private static final int MSG_SIM_SUBSCRIPTION_INFO_CHANGED = 328;
     private static final int MSG_AIRPLANE_MODE_CHANGED = 329;
     private static final int MSG_SERVICE_STATE_CHANGE = 330;
-    private static final int MSG_SCREEN_TURNED_ON = 331;
     private static final int MSG_SCREEN_TURNED_OFF = 332;
     private static final int MSG_DREAMING_STATE_CHANGED = 333;
     private static final int MSG_USER_UNLOCKED = 334;
@@ -310,7 +308,6 @@
     private boolean mSwitchingUser;
 
     private boolean mDeviceInteractive;
-    private boolean mScreenOn;
     private SubscriptionManager mSubscriptionManager;
     private final TelephonyListenerManager mTelephonyListenerManager;
     private List<SubscriptionInfo> mSubscriptionInfo;
@@ -1300,10 +1297,6 @@
         }
     }
 
-    public boolean isScreenOn() {
-        return mScreenOn;
-    }
-
     private void dispatchErrorMessage(CharSequence message) {
         Assert.isMainThread();
         for (int i = 0; i < mCallbacks.size(); i++) {
@@ -1692,29 +1685,10 @@
         updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
     }
 
-    private void handleScreenTurnedOn() {
-        Assert.isMainThread();
-        for (int i = 0; i < mCallbacks.size(); i++) {
-            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
-            if (cb != null) {
-                cb.onScreenTurnedOn();
-            }
-        }
-    }
-
     private void handleScreenTurnedOff() {
-        final String tag = "KeyguardUpdateMonitor#handleScreenTurnedOff";
-        DejankUtils.startDetectingBlockingIpcs(tag);
         Assert.isMainThread();
         mHardwareFingerprintUnavailableRetryCount = 0;
         mHardwareFaceUnavailableRetryCount = 0;
-        for (int i = 0; i < mCallbacks.size(); i++) {
-            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
-            if (cb != null) {
-                cb.onScreenTurnedOff();
-            }
-        }
-        DejankUtils.stopDetectingBlockingIpcs(tag);
     }
 
     private void handleDreamingStateChanged(int dreamStart) {
@@ -1894,11 +1868,8 @@
                     case MSG_SERVICE_STATE_CHANGE:
                         handleServiceStateChange(msg.arg1, (ServiceState) msg.obj);
                         break;
-                    case MSG_SCREEN_TURNED_ON:
-                        handleScreenTurnedOn();
-                        break;
                     case MSG_SCREEN_TURNED_OFF:
-                        Trace.beginSection("KeyguardUpdateMonitor#handler MSG_SCREEN_TURNED_ON");
+                        Trace.beginSection("KeyguardUpdateMonitor#handler MSG_SCREEN_TURNED_OFF");
                         handleScreenTurnedOff();
                         Trace.endSection();
                         break;
@@ -3319,17 +3290,7 @@
         mHandler.sendMessage(mHandler.obtainMessage(MSG_FINISHED_GOING_TO_SLEEP, why, 0));
     }
 
-    public void dispatchScreenTurnedOn() {
-        synchronized (this) {
-            mScreenOn = true;
-        }
-        mHandler.sendEmptyMessage(MSG_SCREEN_TURNED_ON);
-    }
-
     public void dispatchScreenTurnedOff() {
-        synchronized (this) {
-            mScreenOn = false;
-        }
         mHandler.sendEmptyMessage(MSG_SCREEN_TURNED_OFF);
     }
 
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index 8170a81..a74fd15 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -201,22 +201,6 @@
     public void onFinishedGoingToSleep(int why) { }
 
     /**
-     * Called when the screen has been turned on.
-     *
-     * @deprecated use {@link com.android.systemui.keyguard.ScreenLifecycle}.
-     */
-    @Deprecated
-    public void onScreenTurnedOn() { }
-
-    /**
-     * Called when the screen has been turned off.
-     *
-     * @deprecated use {@link com.android.systemui.keyguard.ScreenLifecycle}.
-     */
-    @Deprecated
-    public void onScreenTurnedOff() { }
-
-    /**
      * Called when trust changes for a user.
      */
     public void onTrustChanged(int userId) { }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUserSwitcherPopupMenu.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUserSwitcherPopupMenu.java
index 7b6ce3e..efa5558 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUserSwitcherPopupMenu.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUserSwitcherPopupMenu.java
@@ -18,6 +18,8 @@
 import android.annotation.NonNull;
 import android.content.Context;
 import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.drawable.ShapeDrawable;
 import android.view.MotionEvent;
 import android.view.View;
 import android.widget.ListPopupWindow;
@@ -32,15 +34,6 @@
 public class KeyguardUserSwitcherPopupMenu extends ListPopupWindow {
     private Context mContext;
     private FalsingManager mFalsingManager;
-    private int mLastHeight = -1;
-    private View.OnLayoutChangeListener mLayoutListener = (v, l, t, r, b, ol, ot, or, ob) -> {
-        int height = -v.getMeasuredHeight() + getAnchorView().getHeight();
-        if (height != mLastHeight) {
-            mLastHeight = height;
-            setVerticalOffset(height);
-            KeyguardUserSwitcherPopupMenu.super.show();
-        }
-    };
 
     public KeyguardUserSwitcherPopupMenu(@NonNull Context context,
             @NonNull FalsingManager falsingManager) {
@@ -49,7 +42,7 @@
         mFalsingManager = falsingManager;
         Resources res = mContext.getResources();
         setBackgroundDrawable(
-                res.getDrawable(R.drawable.keyguard_user_switcher_popup_bg, context.getTheme()));
+                res.getDrawable(R.drawable.bouncer_user_switcher_popup_bg, context.getTheme()));
         setModal(true);
         setOverlapAnchor(true);
     }
@@ -63,8 +56,20 @@
         super.show();
         ListView listView = getListView();
 
-        // This will force the popupwindow to show upward instead of drop down
-        listView.addOnLayoutChangeListener(mLayoutListener);
+        listView.setVerticalScrollBarEnabled(false);
+        listView.setHorizontalScrollBarEnabled(false);
+
+        // Creates a transparent spacer between items
+        ShapeDrawable shape = new ShapeDrawable();
+        shape.setAlpha(0);
+        listView.setDivider(shape);
+        listView.setDividerHeight(mContext.getResources().getDimensionPixelSize(
+                R.dimen.bouncer_user_switcher_popup_divider_height));
+
+        int height  = mContext.getResources().getDimensionPixelSize(
+                R.dimen.bouncer_user_switcher_popup_header_height);
+        listView.addHeaderView(createSpacer(height), null, false);
+        listView.addFooterView(createSpacer(height), null, false);
 
         listView.setOnTouchListener((v, ev) -> {
             if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
@@ -72,11 +77,19 @@
             }
             return false;
         });
+        super.show();
     }
 
-    @Override
-    public void dismiss() {
-        getListView().removeOnLayoutChangeListener(mLayoutListener);
-        super.dismiss();
+    private View createSpacer(int height) {
+        return new View(mContext) {
+            @Override
+            protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+                setMeasuredDimension(1, height);
+            }
+
+            @Override
+            public void draw(Canvas canvas) {
+            }
+        };
     }
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java
index fcf1b2c..122f3d7 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java
@@ -70,16 +70,6 @@
     default void onStartedWakingUp() {};
 
     /**
-     * Called when the device started turning on.
-     */
-    default void onScreenTurningOn() {};
-
-    /**
-     * Called when the device has finished turning on.
-     */
-    default void onScreenTurnedOn() {};
-
-    /**
      * Sets whether the Keyguard needs input.
      * @param needsInput
      */
diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerComponent.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerComponent.java
index 5160b7e..0cbf8bc 100644
--- a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerComponent.java
+++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerComponent.java
@@ -16,10 +16,13 @@
 
 package com.android.keyguard.dagger;
 
+import android.view.ViewGroup;
+
 import com.android.keyguard.KeyguardHostViewController;
-import com.android.keyguard.KeyguardRootViewController;
+import com.android.systemui.dagger.qualifiers.RootView;
 import com.android.systemui.statusbar.phone.KeyguardBouncer;
 
+import dagger.BindsInstance;
 import dagger.Subcomponent;
 
 /**
@@ -31,12 +34,9 @@
     /** Simple factory for {@link KeyguardBouncerComponent}. */
     @Subcomponent.Factory
     interface Factory {
-        KeyguardBouncerComponent create();
+        KeyguardBouncerComponent create(@BindsInstance @RootView ViewGroup bouncerContainer);
     }
 
-    /** Returns a {@link KeyguardRootViewController}. */
-    KeyguardRootViewController getKeyguardRootViewController();
-
     /** Returns a {@link KeyguardHostViewController}. */
     KeyguardHostViewController getKeyguardHostViewController();
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerModule.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerModule.java
index 4fad9a9..b3c1158 100644
--- a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerModule.java
+++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerModule.java
@@ -20,7 +20,6 @@
 import android.view.ViewGroup;
 
 import com.android.keyguard.KeyguardHostView;
-import com.android.keyguard.KeyguardMessageArea;
 import com.android.keyguard.KeyguardSecurityContainer;
 import com.android.keyguard.KeyguardSecurityViewFlipper;
 import com.android.systemui.R;
@@ -35,26 +34,16 @@
  */
 @Module
 public interface KeyguardBouncerModule {
-    /** */
-    @Provides
-    @KeyguardBouncerScope
-    @RootView
-    static ViewGroup providesRootView(LayoutInflater layoutInflater) {
-        return (ViewGroup) layoutInflater.inflate(R.layout.keyguard_bouncer, null);
-    }
 
     /** */
     @Provides
     @KeyguardBouncerScope
-    static KeyguardMessageArea providesKeyguardMessageArea(@RootView ViewGroup viewGroup) {
-        return viewGroup.findViewById(R.id.keyguard_message_area);
-    }
-
-    /** */
-    @Provides
-    @KeyguardBouncerScope
-    static KeyguardHostView providesKeyguardHostView(@RootView ViewGroup rootView) {
-        return rootView.findViewById(R.id.keyguard_host_view);
+    static KeyguardHostView providesKeyguardHostView(@RootView ViewGroup rootView,
+            LayoutInflater layoutInflater) {
+        KeyguardHostView hostView = (KeyguardHostView) layoutInflater.inflate(
+                R.layout.keyguard_host_view, rootView, false);
+        rootView.addView(hostView);
+        return hostView;
     }
 
     /** */
diff --git a/packages/SystemUI/src/com/android/keyguard/mediator/ScreenOnCoordinator.kt b/packages/SystemUI/src/com/android/keyguard/mediator/ScreenOnCoordinator.kt
new file mode 100644
index 0000000..705cf6d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/mediator/ScreenOnCoordinator.kt
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.mediator
+
+import android.os.Trace
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.ScreenLifecycle
+import com.android.systemui.util.concurrency.Execution
+import com.android.systemui.util.concurrency.PendingTasksContainer
+import com.android.systemui.unfold.SysUIUnfoldComponent
+import com.android.systemui.util.kotlin.getOrNull
+
+import java.util.Optional
+
+import javax.inject.Inject
+
+/**
+ * Coordinates screen on/turning on animations for the KeyguardViewMediator. Specifically for
+ * screen on events, this will invoke the onDrawn Runnable after all tasks have completed. This
+ * should route back to the KeyguardService, which informs the system_server that keyguard has
+ * drawn.
+ */
+@SysUISingleton
+class ScreenOnCoordinator @Inject constructor(
+    screenLifecycle: ScreenLifecycle,
+    unfoldComponent: Optional<SysUIUnfoldComponent>,
+    private val execution: Execution
+) : ScreenLifecycle.Observer {
+
+    private val unfoldLightRevealAnimation = unfoldComponent.map(
+        SysUIUnfoldComponent::getUnfoldLightRevealOverlayAnimation).getOrNull()
+    private val foldAodAnimationController = unfoldComponent.map(
+        SysUIUnfoldComponent::getFoldAodAnimationController).getOrNull()
+    private val pendingTasks = PendingTasksContainer()
+
+    private var wakeAndUnlockingTask: Runnable? = null
+    var wakeAndUnlocking = false
+        set(value) {
+            if (!value && field) {
+                // When updating the value back to false, mark the task complete in order to
+                // callback onDrawn
+                wakeAndUnlockingTask?.run()
+                wakeAndUnlockingTask = null
+            }
+            field = value
+        }
+
+    init {
+        screenLifecycle.addObserver(this)
+    }
+
+    /**
+     * When turning on, registers tasks that may need to run before invoking [onDrawn].
+     */
+    override fun onScreenTurningOn(onDrawn: Runnable) {
+        execution.assertIsMainThread()
+        Trace.beginSection("ScreenOnCoordinator#onScreenTurningOn")
+
+        pendingTasks.reset()
+
+        unfoldLightRevealAnimation?.onScreenTurningOn(pendingTasks.registerTask("unfold-reveal"))
+        foldAodAnimationController?.onScreenTurningOn(pendingTasks.registerTask("fold-to-aod"))
+
+        if (wakeAndUnlocking) {
+            wakeAndUnlockingTask = pendingTasks.registerTask("wake-and-unlocking")
+        }
+
+        pendingTasks.onTasksComplete { onDrawn.run() }
+        Trace.endSection()
+    }
+
+    override fun onScreenTurnedOn() {
+        execution.assertIsMainThread()
+
+        foldAodAnimationController?.onScreenTurnedOn()
+
+        pendingTasks.reset()
+    }
+
+    override fun onScreenTurnedOff() {
+        wakeAndUnlockingTask = null
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index 6edf2a8..1ac9016 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -49,7 +49,6 @@
 import android.hardware.fingerprint.IUdfpsHbmListener;
 import android.os.Bundle;
 import android.os.Handler;
-import android.os.Looper;
 import android.os.RemoteException;
 import android.util.Log;
 import android.util.SparseBooleanArray;
@@ -65,6 +64,7 @@
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.doze.DozeReceiver;
 import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.util.concurrency.Execution;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -92,15 +92,20 @@
     private static final boolean DEBUG = true;
     private static final int SENSOR_PRIVACY_DELAY = 500;
 
-    private final Handler mHandler = new Handler(Looper.getMainLooper());
+    private final Handler mHandler;
+    private final Execution mExecution;
     private final CommandQueue mCommandQueue;
     private final ActivityTaskManager mActivityTaskManager;
-    @Nullable private final FingerprintManager mFingerprintManager;
-    @Nullable private final FaceManager mFaceManager;
+    @Nullable
+    private final FingerprintManager mFingerprintManager;
+    @Nullable
+    private final FaceManager mFaceManager;
     private final Provider<UdfpsController> mUdfpsControllerFactory;
     private final Provider<SidefpsController> mSidefpsControllerFactory;
-    @Nullable private final PointF mFaceAuthSensorLocation;
-    @Nullable private PointF mFingerprintLocation;
+    @Nullable
+    private final PointF mFaceAuthSensorLocation;
+    @Nullable
+    private PointF mFingerprintLocation;
     private final Set<Callback> mCallbacks = new HashSet<>();
 
     // TODO: These should just be saved from onSaveState
@@ -133,62 +138,27 @@
         }
     }
 
-    private final FingerprintStateListener mFingerprintStateListener =
-            new FingerprintStateListener() {
-        @Override
-        public void onEnrollmentsChanged(int userId, int sensorId, boolean hasEnrollments) {
-            Log.d(TAG, "onEnrollmentsChanged, userId: " + userId
-                    + ", sensorId: " + sensorId
-                    + ", hasEnrollments: " + hasEnrollments);
-            for (FingerprintSensorPropertiesInternal prop : mUdfpsProps) {
-                if (prop.sensorId == sensorId) {
-                    mUdfpsEnrolledForUser.put(userId, hasEnrollments);
-                }
-            }
-
-            for (Callback cb : mCallbacks) {
-                cb.onEnrollmentsChanged();
-            }
-        }
-    };
-
-    @NonNull
     private final IFingerprintAuthenticatorsRegisteredCallback
             mFingerprintAuthenticatorsRegisteredCallback =
             new IFingerprintAuthenticatorsRegisteredCallback.Stub() {
-                @Override public void onAllAuthenticatorsRegistered(
+                @Override
+                public void onAllAuthenticatorsRegistered(
                         List<FingerprintSensorPropertiesInternal> sensors) {
-                    if (DEBUG) {
-                        Log.d(TAG, "onFingerprintProvidersAvailable | sensors: " + Arrays.toString(
-                                sensors.toArray()));
-                    }
-                    mFpProps = sensors;
-                    List<FingerprintSensorPropertiesInternal> udfpsProps = new ArrayList<>();
-                    List<FingerprintSensorPropertiesInternal> sidefpsProps = new ArrayList<>();
-                    for (FingerprintSensorPropertiesInternal props : mFpProps) {
-                        if (props.isAnyUdfpsType()) {
-                            udfpsProps.add(props);
-                        }
-                        if (props.isAnySidefpsType()) {
-                            sidefpsProps.add(props);
-                        }
-                    }
-                    mUdfpsProps = !udfpsProps.isEmpty() ? udfpsProps : null;
-                    if (mUdfpsProps != null) {
-                        mUdfpsController = mUdfpsControllerFactory.get();
-                    }
-                    mSidefpsProps = !sidefpsProps.isEmpty() ? sidefpsProps : null;
-                    if (mSidefpsProps != null) {
-                        mSidefpsController = mSidefpsControllerFactory.get();
-                    }
-
-                    for (Callback cb : mCallbacks) {
-                        cb.onAllAuthenticatorsRegistered();
-                    }
+                    mHandler.post(() -> handleAllAuthenticatorsRegistered(sensors));
                 }
             };
 
-    @VisibleForTesting final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+    private final FingerprintStateListener mFingerprintStateListener =
+            new FingerprintStateListener() {
+                @Override
+                public void onEnrollmentsChanged(int userId, int sensorId, boolean hasEnrollments) {
+                    mHandler.post(
+                            () -> handleEnrollmentsChanged(userId, sensorId, hasEnrollments));
+                }
+            };
+
+    @VisibleForTesting
+    final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
             if (mCurrentDialog != null
@@ -212,6 +182,7 @@
     };
 
     private void handleTaskStackChanged() {
+        mExecution.assertIsMainThread();
         if (mCurrentDialog != null) {
             try {
                 final String clientPackage = mCurrentDialog.getOpPackageName();
@@ -241,6 +212,56 @@
         }
     }
 
+    private void handleAllAuthenticatorsRegistered(
+            List<FingerprintSensorPropertiesInternal> sensors) {
+        mExecution.assertIsMainThread();
+        if (DEBUG) {
+            Log.d(TAG, "handleAllAuthenticatorsRegistered | sensors: " + Arrays.toString(
+                    sensors.toArray()));
+        }
+        mFpProps = sensors;
+        List<FingerprintSensorPropertiesInternal> udfpsProps = new ArrayList<>();
+        List<FingerprintSensorPropertiesInternal> sidefpsProps = new ArrayList<>();
+        for (FingerprintSensorPropertiesInternal props : mFpProps) {
+            if (props.isAnyUdfpsType()) {
+                udfpsProps.add(props);
+            }
+            if (props.isAnySidefpsType()) {
+                sidefpsProps.add(props);
+            }
+        }
+        mUdfpsProps = !udfpsProps.isEmpty() ? udfpsProps : null;
+        if (mUdfpsProps != null) {
+            mUdfpsController = mUdfpsControllerFactory.get();
+        }
+        mSidefpsProps = !sidefpsProps.isEmpty() ? sidefpsProps : null;
+        if (mSidefpsProps != null) {
+            mSidefpsController = mSidefpsControllerFactory.get();
+        }
+        for (Callback cb : mCallbacks) {
+            cb.onAllAuthenticatorsRegistered();
+        }
+        mFingerprintManager.registerFingerprintStateListener(mFingerprintStateListener);
+    }
+
+    private void handleEnrollmentsChanged(int userId, int sensorId, boolean hasEnrollments) {
+        mExecution.assertIsMainThread();
+        Log.d(TAG, "handleEnrollmentsChanged, userId: " + userId + ", sensorId: " + sensorId
+                + ", hasEnrollments: " + hasEnrollments);
+        if (mUdfpsProps == null) {
+            Log.d(TAG, "handleEnrollmentsChanged, mUdfpsProps is null");
+        } else {
+            for (FingerprintSensorPropertiesInternal prop : mUdfpsProps) {
+                if (prop.sensorId == sensorId) {
+                    mUdfpsEnrolledForUser.put(userId, hasEnrollments);
+                }
+            }
+        }
+        for (Callback cb : mCallbacks) {
+            cb.onEnrollmentsChanged();
+        }
+    }
+
     /**
      * Adds a callback. See {@link Callback}.
      */
@@ -449,6 +470,7 @@
 
     @Inject
     public AuthController(Context context,
+            Execution execution,
             CommandQueue commandQueue,
             ActivityTaskManager activityTaskManager,
             @NonNull WindowManager windowManager,
@@ -459,6 +481,8 @@
             @NonNull DisplayManager displayManager,
             @Main Handler handler) {
         super(context);
+        mExecution = execution;
+        mHandler = handler;
         mCommandQueue = commandQueue;
         mActivityTaskManager = activityTaskManager;
         mFingerprintManager = fingerprintManager;
@@ -470,7 +494,7 @@
         mOrientationListener = new BiometricDisplayListener(
                 context,
                 displayManager,
-                handler,
+                mHandler,
                 BiometricDisplayListener.SensorType.Generic.INSTANCE,
                 () -> {
                     onOrientationChanged();
@@ -521,7 +545,6 @@
         if (mFingerprintManager != null) {
             mFingerprintManager.addAuthenticatorsRegisteredCallback(
                     mFingerprintAuthenticatorsRegisteredCallback);
-            mFingerprintManager.registerFingerprintStateListener(mFingerprintStateListener);
         }
 
         mTaskStackListener = new BiometricTaskStackListener();
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
index 90a1e5e..f82ea79 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
@@ -80,11 +80,6 @@
     private var circleReveal: LightRevealEffect? = null
 
     private var udfpsController: UdfpsController? = null
-
-    private var dwellScale = 2f
-    private var expandedDwellScale = 2.5f
-    private var aodDwellScale = 1.9f
-    private var aodExpandedDwellScale = 2.3f
     private var udfpsRadius: Float = -1f
 
     override fun onInit() {
@@ -128,7 +123,7 @@
         updateSensorLocation()
         if (biometricSourceType == BiometricSourceType.FINGERPRINT &&
             fingerprintSensorLocation != null) {
-            mView.setSensorLocation(fingerprintSensorLocation!!)
+            mView.setFingerprintSensorLocation(fingerprintSensorLocation!!, udfpsRadius)
             showUnlockedRipple()
         } else if (biometricSourceType == BiometricSourceType.FACE &&
             faceSensorLocation != null) {
@@ -241,24 +236,12 @@
     }
 
     private fun updateRippleColor() {
-        mView.setColor(
-            Utils.getColorAttr(sysuiContext, android.R.attr.colorAccent).defaultColor)
+        mView.setLockScreenColor(Utils.getColorAttrDefaultColor(sysuiContext,
+                R.attr.wallpaperTextColorAccent))
     }
 
     private fun showDwellRipple() {
-        if (statusBarStateController.isDozing) {
-            mView.startDwellRipple(
-                    /* startRadius */ udfpsRadius,
-                    /* endRadius */ udfpsRadius * aodDwellScale,
-                    /* expandedRadius */ udfpsRadius * aodExpandedDwellScale,
-                    /* isDozing */ true)
-        } else {
-            mView.startDwellRipple(
-                    /* startRadius */ udfpsRadius,
-                    /* endRadius */ udfpsRadius * dwellScale,
-                    /* expandedRadius */ udfpsRadius * expandedDwellScale,
-                    /* isDozing */ false)
-        }
+        mView.startDwellRipple(statusBarStateController.isDozing)
     }
 
     private val keyguardUpdateMonitorCallback =
@@ -295,7 +278,7 @@
                     return
                 }
 
-                mView.setSensorLocation(fingerprintSensorLocation!!)
+                mView.setFingerprintSensorLocation(fingerprintSensorLocation!!, udfpsRadius)
                 showDwellRipple()
             }
 
@@ -307,8 +290,8 @@
     private val authControllerCallback =
         object : AuthController.Callback {
             override fun onAllAuthenticatorsRegistered() {
-                updateSensorLocation()
                 updateUdfpsDependentParams()
+                updateSensorLocation()
             }
 
             override fun onEnrollmentsChanged() {
@@ -329,20 +312,6 @@
     }
 
     inner class AuthRippleCommand : Command {
-        fun printLockScreenDwellInfo(pw: PrintWriter) {
-            pw.println("lock screen dwell ripple: " +
-                    "\n\tsensorLocation=$fingerprintSensorLocation" +
-                    "\n\tdwellScale=$dwellScale" +
-                    "\n\tdwellExpand=$expandedDwellScale")
-        }
-
-        fun printAodDwellInfo(pw: PrintWriter) {
-            pw.println("aod dwell ripple: " +
-                    "\n\tsensorLocation=$fingerprintSensorLocation" +
-                    "\n\tdwellScale=$aodDwellScale" +
-                    "\n\tdwellExpand=$aodExpandedDwellScale")
-        }
-
         override fun execute(pw: PrintWriter, args: List<String>) {
             if (args.isEmpty()) {
                 invalidCommand(pw)
@@ -350,11 +319,9 @@
                 when (args[0]) {
                     "dwell" -> {
                         showDwellRipple()
-                        if (statusBarStateController.isDozing) {
-                            printAodDwellInfo(pw)
-                        } else {
-                            printLockScreenDwellInfo(pw)
-                        }
+                        pw.println("lock screen dwell ripple: " +
+                                "\n\tsensorLocation=$fingerprintSensorLocation" +
+                                "\n\tudfpsRadius=$udfpsRadius")
                     }
                     "fingerprint" -> {
                         updateSensorLocation()
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt
index c6d26ff..d673630 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt
@@ -21,6 +21,7 @@
 import android.animation.ValueAnimator
 import android.content.Context
 import android.graphics.Canvas
+import android.graphics.Color
 import android.graphics.Paint
 import android.graphics.PointF
 import android.util.AttributeSet
@@ -28,6 +29,7 @@
 import android.view.animation.PathInterpolator
 import com.android.internal.graphics.ColorUtils
 import com.android.systemui.animation.Interpolators
+import com.android.systemui.statusbar.charging.DwellRippleShader
 import com.android.systemui.statusbar.charging.RippleShader
 
 private const val RIPPLE_SPARKLE_STRENGTH: Float = 0.4f
@@ -43,23 +45,32 @@
 class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, attrs) {
     private val retractInterpolator = PathInterpolator(.05f, .93f, .1f, 1f)
 
-    private val dwellPulseDuration = 50L
-    private val dwellAlphaDuration = dwellPulseDuration
-    private val dwellAlpha: Float = 1f
-    private val dwellExpandDuration = 1200L - dwellPulseDuration
+    private val dwellPulseDuration = 100L
+    private val dwellExpandDuration = 2000L - dwellPulseDuration
 
-    private val aodDwellPulseDuration = 50L
-    private var aodDwellAlphaDuration = aodDwellPulseDuration
-    private var aodDwellAlpha: Float = .8f
-    private var aodDwellExpandDuration = 1200L - aodDwellPulseDuration
+    private var drawDwell: Boolean = false
+    private var drawRipple: Boolean = false
 
+    private var lockScreenColorVal = Color.WHITE
     private val retractDuration = 400L
     private var alphaInDuration: Long = 0
     private var unlockedRippleInProgress: Boolean = false
+    private val dwellShader = DwellRippleShader()
+    private val dwellPaint = Paint()
     private val rippleShader = RippleShader()
     private val ripplePaint = Paint()
     private var retractAnimator: Animator? = null
     private var dwellPulseOutAnimator: Animator? = null
+    private var dwellRadius: Float = 0f
+        set(value) {
+            dwellShader.maxRadius = value
+            field = value
+        }
+    private var dwellOrigin: PointF = PointF()
+        set(value) {
+            dwellShader.origin = value
+            field = value
+        }
     private var radius: Float = 0f
         set(value) {
             rippleShader.radius = value
@@ -76,6 +87,11 @@
         rippleShader.progress = 0f
         rippleShader.sparkleStrength = RIPPLE_SPARKLE_STRENGTH
         ripplePaint.shader = rippleShader
+
+        dwellShader.color = 0xffffffff.toInt() // default color
+        dwellShader.progress = 0f
+        dwellShader.distortionStrength = .4f
+        dwellPaint.shader = dwellShader
         visibility = GONE
     }
 
@@ -84,6 +100,13 @@
         radius = maxOf(location.x, location.y, width - location.x, height - location.y).toFloat()
     }
 
+    fun setFingerprintSensorLocation(location: PointF, sensorRadius: Float) {
+        origin = location
+        radius = maxOf(location.x, location.y, width - location.x, height - location.y).toFloat()
+        dwellOrigin = location
+        dwellRadius = sensorRadius * 1.5f
+    }
+
     fun setAlphaInDuration(duration: Long) {
         alphaInDuration = duration
     }
@@ -97,14 +120,14 @@
         }
 
         if (dwellPulseOutAnimator?.isRunning == true) {
-            val retractRippleAnimator = ValueAnimator.ofFloat(rippleShader.progress, 0f)
+            val retractRippleAnimator = ValueAnimator.ofFloat(dwellShader.progress, 0f)
                     .apply {
                 interpolator = retractInterpolator
                 duration = retractDuration
                 addUpdateListener { animator ->
                     val now = animator.currentPlayTime
-                    rippleShader.progress = animator.animatedValue as Float
-                    rippleShader.time = now.toFloat()
+                    dwellShader.progress = animator.animatedValue as Float
+                    dwellShader.time = now.toFloat()
 
                     invalidate()
                 }
@@ -114,8 +137,8 @@
                 interpolator = Interpolators.LINEAR
                 duration = retractDuration
                 addUpdateListener { animator ->
-                    rippleShader.color = ColorUtils.setAlphaComponent(
-                            rippleShader.color,
+                    dwellShader.color = ColorUtils.setAlphaComponent(
+                            dwellShader.color,
                             animator.animatedValue as Int
                     )
                     invalidate()
@@ -127,13 +150,12 @@
                 addListener(object : AnimatorListenerAdapter() {
                     override fun onAnimationStart(animation: Animator?) {
                         dwellPulseOutAnimator?.cancel()
-                        rippleShader.shouldFadeOutRipple = false
-                        visibility = VISIBLE
+                        drawDwell = true
                     }
 
                     override fun onAnimationEnd(animation: Animator?) {
-                        visibility = GONE
-                        resetRippleAlpha()
+                        drawDwell = false
+                        resetDwellAlpha()
                     }
                 })
                 start()
@@ -142,101 +164,54 @@
     }
 
     /**
-     * Ripple that moves animates from an outer ripple ring of
-     *      startRadius => endRadius => expandedRadius
+     * Plays a ripple animation that grows to the dwellRadius with distortion.
      */
-    fun startDwellRipple(
-        startRadius: Float,
-        endRadius: Float,
-        expandedRadius: Float,
-        isDozing: Boolean
-    ) {
+    fun startDwellRipple(isDozing: Boolean) {
         if (unlockedRippleInProgress || dwellPulseOutAnimator?.isRunning == true) {
             return
         }
 
-        // we divide by 4 because the desired startRadius and endRadius is for the ripple's outer
-        // ring see RippleShader
-        val startDwellProgress = startRadius / radius / 4f
-        val endInitialDwellProgress = endRadius / radius / 4f
-        val endExpandDwellProgress = expandedRadius / radius / 4f
+        updateDwellRippleColor(isDozing)
 
-        val alpha = if (isDozing) aodDwellAlpha else dwellAlpha
-        val pulseOutEndAlpha = (255 * alpha).toInt()
-        val expandDwellEndAlpha = kotlin.math.min((255 * (alpha + .25f)).toInt(), 255)
-        val dwellPulseOutRippleAnimator = ValueAnimator.ofFloat(startDwellProgress,
-                endInitialDwellProgress).apply {
-            interpolator = Interpolators.LINEAR_OUT_SLOW_IN
-            duration = if (isDozing) aodDwellPulseDuration else dwellPulseDuration
+        val dwellPulseOutRippleAnimator = ValueAnimator.ofFloat(0f, .8f).apply {
+            interpolator = Interpolators.LINEAR
+            duration = dwellPulseDuration
             addUpdateListener { animator ->
                 val now = animator.currentPlayTime
-                rippleShader.progress = animator.animatedValue as Float
-                rippleShader.time = now.toFloat()
+                dwellShader.progress = animator.animatedValue as Float
+                dwellShader.time = now.toFloat()
 
                 invalidate()
             }
         }
 
-        val dwellPulseOutAlphaAnimator = ValueAnimator.ofInt(0, pulseOutEndAlpha).apply {
-            interpolator = Interpolators.LINEAR
-            duration = if (isDozing) aodDwellAlphaDuration else dwellAlphaDuration
-            addUpdateListener { animator ->
-                rippleShader.color = ColorUtils.setAlphaComponent(
-                        rippleShader.color,
-                        animator.animatedValue as Int
-                )
-                invalidate()
-            }
-        }
-
         // slowly animate outwards until we receive a call to retractRipple or startUnlockedRipple
-        val expandDwellRippleAnimator = ValueAnimator.ofFloat(endInitialDwellProgress,
-                endExpandDwellProgress).apply {
+        val expandDwellRippleAnimator = ValueAnimator.ofFloat(.8f, 1f).apply {
             interpolator = Interpolators.LINEAR_OUT_SLOW_IN
-            duration = if (isDozing) aodDwellExpandDuration else dwellExpandDuration
+            duration = dwellExpandDuration
             addUpdateListener { animator ->
                 val now = animator.currentPlayTime
-                rippleShader.progress = animator.animatedValue as Float
-                rippleShader.time = now.toFloat()
+                dwellShader.progress = animator.animatedValue as Float
+                dwellShader.time = now.toFloat()
 
                 invalidate()
             }
         }
 
-        val expandDwellAlphaAnimator = ValueAnimator.ofInt(pulseOutEndAlpha, expandDwellEndAlpha)
-                .apply {
-            interpolator = Interpolators.LINEAR
-            duration = if (isDozing) aodDwellExpandDuration else dwellExpandDuration
-            addUpdateListener { animator ->
-                rippleShader.color = ColorUtils.setAlphaComponent(
-                        rippleShader.color,
-                        animator.animatedValue as Int
-                )
-                invalidate()
-            }
-        }
-
-        val initialDwellPulseOutAnimator = AnimatorSet().apply {
-            playTogether(dwellPulseOutRippleAnimator, dwellPulseOutAlphaAnimator)
-        }
-        val expandDwellAnimator = AnimatorSet().apply {
-            playTogether(expandDwellRippleAnimator, expandDwellAlphaAnimator)
-        }
-
         dwellPulseOutAnimator = AnimatorSet().apply {
             playSequentially(
-                    initialDwellPulseOutAnimator,
-                    expandDwellAnimator
+                    dwellPulseOutRippleAnimator,
+                    expandDwellRippleAnimator
             )
             addListener(object : AnimatorListenerAdapter() {
                 override fun onAnimationStart(animation: Animator?) {
                     retractAnimator?.cancel()
-                    rippleShader.shouldFadeOutRipple = false
                     visibility = VISIBLE
+                    drawDwell = true
                 }
 
                 override fun onAnimationEnd(animation: Animator?) {
-                    visibility = GONE
+                    drawDwell = false
                     resetRippleAlpha()
                 }
             })
@@ -252,16 +227,7 @@
             return // Ignore if ripple effect is already playing
         }
 
-        var rippleStart = 0f
-        var alphaDuration = alphaInDuration
-        if (dwellPulseOutAnimator?.isRunning == true || retractAnimator?.isRunning == true) {
-            rippleStart = rippleShader.progress
-            alphaDuration = 0
-            dwellPulseOutAnimator?.cancel()
-            retractAnimator?.cancel()
-        }
-
-        val rippleAnimator = ValueAnimator.ofFloat(rippleStart, 1f).apply {
+        val rippleAnimator = ValueAnimator.ofFloat(0f, 1f).apply {
             interpolator = Interpolators.LINEAR_OUT_SLOW_IN
             duration = AuthRippleController.RIPPLE_ANIMATION_DURATION
             addUpdateListener { animator ->
@@ -274,7 +240,7 @@
         }
 
         val alphaInAnimator = ValueAnimator.ofInt(0, 255).apply {
-            duration = alphaDuration
+            duration = alphaInDuration
             addUpdateListener { animator ->
                 rippleShader.color = ColorUtils.setAlphaComponent(
                     rippleShader.color,
@@ -293,12 +259,14 @@
                 override fun onAnimationStart(animation: Animator?) {
                     unlockedRippleInProgress = true
                     rippleShader.shouldFadeOutRipple = true
+                    drawRipple = true
                     visibility = VISIBLE
                 }
 
                 override fun onAnimationEnd(animation: Animator?) {
                     onAnimationEnd?.run()
                     unlockedRippleInProgress = false
+                    drawRipple = false
                     visibility = GONE
                 }
             })
@@ -313,17 +281,42 @@
         )
     }
 
-    fun setColor(color: Int) {
-        rippleShader.color = color
+    fun setLockScreenColor(color: Int) {
+        lockScreenColorVal = color
+        rippleShader.color = lockScreenColorVal
         resetRippleAlpha()
     }
 
+    fun updateDwellRippleColor(isDozing: Boolean) {
+        if (isDozing) {
+            dwellShader.color = Color.WHITE
+        } else {
+            dwellShader.color = lockScreenColorVal
+        }
+        resetDwellAlpha()
+    }
+
+    fun resetDwellAlpha() {
+        dwellShader.color = ColorUtils.setAlphaComponent(
+                dwellShader.color,
+                255
+        )
+    }
+
     override fun onDraw(canvas: Canvas?) {
         // To reduce overdraw, we mask the effect to a circle whose radius is big enough to cover
         // 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 * 2f
-        canvas?.drawCircle(origin.x, origin.y, maskRadius, ripplePaint)
+        if (drawDwell) {
+            val maskRadius = (1 - (1 - dwellShader.progress) * (1 - dwellShader.progress) *
+                    (1 - dwellShader.progress)) * dwellRadius * 2f
+            canvas?.drawCircle(dwellOrigin.x, dwellOrigin.y, maskRadius, dwellPaint)
+        }
+
+        if (drawRipple) {
+            val mask = (1 - (1 - rippleShader.progress) * (1 - rippleShader.progress) *
+                    (1 - rippleShader.progress)) * radius * 2f
+            canvas?.drawCircle(origin.x, origin.y, mask, ripplePaint)
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationView.java
index e7f6374..7fdb5ea 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationView.java
@@ -33,7 +33,7 @@
  * - sends sensor rect updates to fingerprint drawable
  * - optionally can override dozeTimeTick to adjust views for burn-in mitigation
  */
-abstract class UdfpsAnimationView extends FrameLayout {
+public abstract class UdfpsAnimationView extends FrameLayout {
     // mAlpha takes into consideration the status bar expansion amount to fade out icon when
     // the status bar is expanded
     private int mAlpha;
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.java
deleted file mode 100644
index 73e3aec..0000000
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.java
+++ /dev/null
@@ -1,202 +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.biometrics;
-
-import android.annotation.NonNull;
-import android.graphics.PointF;
-import android.graphics.RectF;
-
-import com.android.systemui.Dumpable;
-import com.android.systemui.dump.DumpManager;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.phone.SystemUIDialogManager;
-import com.android.systemui.statusbar.phone.panelstate.PanelExpansionListener;
-import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
-import com.android.systemui.util.ViewController;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-
-/**
- * Handles:
- * 1. registering for listeners when its view is attached and unregistering on view detached
- * 2. pausing udfps when fingerprintManager may still be running but we temporarily want to hide
- * the affordance. this allows us to fade the view in and out nicely (see shouldPauseAuth)
- * 3. sending events to its view including:
- *      - illumination events
- *      - sensor position changes
- *      - doze time event
- */
-abstract class UdfpsAnimationViewController<T extends UdfpsAnimationView>
-        extends ViewController<T> implements Dumpable {
-    @NonNull final StatusBarStateController mStatusBarStateController;
-    @NonNull final PanelExpansionStateManager mPanelExpansionStateManager;
-    @NonNull final SystemUIDialogManager mDialogManager;
-    @NonNull final DumpManager mDumpManger;
-
-    boolean mNotificationShadeVisible;
-
-    protected UdfpsAnimationViewController(
-            T view,
-            @NonNull StatusBarStateController statusBarStateController,
-            @NonNull PanelExpansionStateManager panelExpansionStateManager,
-            @NonNull SystemUIDialogManager dialogManager,
-            @NonNull DumpManager dumpManager) {
-        super(view);
-        mStatusBarStateController = statusBarStateController;
-        mPanelExpansionStateManager = panelExpansionStateManager;
-        mDialogManager = dialogManager;
-        mDumpManger = dumpManager;
-    }
-
-    abstract @NonNull String getTag();
-
-    @Override
-    protected void onViewAttached() {
-        mPanelExpansionStateManager.addExpansionListener(mPanelExpansionListener);
-        mDialogManager.registerListener(mDialogListener);
-        mDumpManger.registerDumpable(getDumpTag(), this);
-    }
-
-    @Override
-    protected void onViewDetached() {
-        mPanelExpansionStateManager.removeExpansionListener(mPanelExpansionListener);
-        mDialogManager.unregisterListener(mDialogListener);
-        mDumpManger.unregisterDumpable(getDumpTag());
-    }
-
-    /**
-     * in some cases, onViewAttached is called for the newly added view using an instance of
-     * this controller before onViewDetached is called on the previous view, so we must have a
-     * unique dump tag per instance of this class
-     * @return a unique tag for this instance of this class
-     */
-    private String getDumpTag() {
-        return getTag() + " (" + this + ")";
-    }
-
-    @Override
-    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        pw.println("mNotificationShadeVisible=" + mNotificationShadeVisible);
-        pw.println("shouldPauseAuth()=" + shouldPauseAuth());
-        pw.println("isPauseAuth=" + mView.isPauseAuth());
-    }
-
-    /**
-     * Returns true if the fingerprint manager is running but we want to temporarily pause
-     * authentication.
-     */
-    boolean shouldPauseAuth() {
-        return mNotificationShadeVisible
-                || mDialogManager.shouldHideAffordance();
-    }
-
-    /**
-     * Send pause auth update to our view.
-     */
-    void updatePauseAuth() {
-        if (mView.setPauseAuth(shouldPauseAuth())) {
-            mView.postInvalidate();
-        }
-    }
-
-    /**
-     * Send sensor position change to our view. This rect contains paddingX and paddingY.
-     */
-    void onSensorRectUpdated(RectF sensorRect) {
-        mView.onSensorRectUpdated(sensorRect);
-    }
-
-    /**
-     * Send dozeTimeTick to view in case it wants to handle its burn-in offset.
-     */
-    void dozeTimeTick() {
-        if (mView.dozeTimeTick()) {
-            mView.postInvalidate();
-        }
-    }
-
-    /**
-     * @return the amount of translation needed if the view currently requires the user to touch
-     *         somewhere other than the exact center of the sensor. For example, this can happen
-     *         during guided enrollment.
-     */
-    PointF getTouchTranslation() {
-        return new PointF(0, 0);
-    }
-
-    /**
-     * X-Padding to add to left and right of the sensor rectangle area to increase the size of our
-     * window to draw within.
-     * @return
-     */
-    int getPaddingX() {
-        return 0;
-    }
-
-    /**
-     * Y-Padding to add to top and bottom of the sensor rectangle area to increase the size of our
-     * window to draw within.
-     */
-    int getPaddingY() {
-        return 0;
-    }
-
-    /**
-     * Udfps has started illuminating and the fingerprint manager is working on authenticating.
-     */
-    void onIlluminationStarting() {
-        mView.onIlluminationStarting();
-        mView.postInvalidate();
-    }
-
-    /**
-     * Udfps has stopped illuminating and the fingerprint manager is no longer attempting to
-     * authenticate.
-     */
-    void onIlluminationStopped() {
-        mView.onIlluminationStopped();
-        mView.postInvalidate();
-    }
-
-    /**
-     * Whether to listen for touches outside of the view.
-     */
-    boolean listenForTouchesOutsideView() {
-        return false;
-    }
-
-    /**
-     * Called on touches outside of the view if listenForTouchesOutsideView returns true
-     */
-    void onTouchOutsideView() { }
-
-    private final PanelExpansionListener mPanelExpansionListener = new PanelExpansionListener() {
-        @Override
-        public void onPanelExpansionChanged(
-                float fraction, boolean expanded, boolean tracking) {
-            // Notification shade can be expanded but not visible (fraction: 0.0), for example
-            // when a heads-up notification (HUN) is showing.
-            mNotificationShadeVisible = expanded && fraction > 0f;
-            mView.onExpansionChanged(fraction);
-            updatePauseAuth();
-        }
-    };
-
-    private final SystemUIDialogManager.Listener mDialogListener =
-            (shouldHide) -> updatePauseAuth();
-}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.kt
new file mode 100644
index 0000000..c33cd8d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.kt
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.biometrics
+
+import android.graphics.PointF
+import android.graphics.RectF
+import com.android.systemui.Dumpable
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.statusbar.phone.SystemUIDialogManager
+import com.android.systemui.statusbar.phone.panelstate.PanelExpansionListener
+import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager
+import com.android.systemui.util.ViewController
+import java.io.FileDescriptor
+import java.io.PrintWriter
+
+/**
+ * Handles:
+ * 1. registering for listeners when its view is attached and unregistering on view detached
+ * 2. pausing udfps when fingerprintManager may still be running but we temporarily want to hide
+ * the affordance. this allows us to fade the view in and out nicely (see shouldPauseAuth)
+ * 3. sending events to its view including:
+ * - illumination events
+ * - sensor position changes
+ * - doze time event
+ */
+abstract class UdfpsAnimationViewController<T : UdfpsAnimationView>(
+    view: T,
+    protected val statusBarStateController: StatusBarStateController,
+    protected val panelExpansionStateManager: PanelExpansionStateManager,
+    protected val dialogManager: SystemUIDialogManager,
+    private val dumpManager: DumpManager
+) : ViewController<T>(view), Dumpable {
+
+    protected abstract val tag: String
+
+    private val view: T
+        get() = mView!!
+
+    private val dialogListener = SystemUIDialogManager.Listener { updatePauseAuth() }
+
+    private val panelExpansionListener =
+        PanelExpansionListener { fraction, expanded, tracking ->
+            // Notification shade can be expanded but not visible (fraction: 0.0), for example
+            // when a heads-up notification (HUN) is showing.
+            notificationShadeVisible = expanded && fraction > 0f
+            view.onExpansionChanged(fraction)
+            updatePauseAuth()
+        }
+
+    /** If the notification shade is visible. */
+    var notificationShadeVisible: Boolean = false
+
+    /**
+     * The amount of translation needed if the view currently requires the user to touch
+     * somewhere other than the exact center of the sensor. For example, this can happen
+     * during guided enrollment.
+     */
+    open val touchTranslation: PointF = PointF(0f, 0f)
+
+    /**
+     * X-Padding to add to left and right of the sensor rectangle area to increase the size of our
+     * window to draw within.
+     */
+    open val paddingX: Int = 0
+
+    /**
+     * Y-Padding to add to top and bottom of the sensor rectangle area to increase the size of our
+     * window to draw within.
+     */
+    open val paddingY: Int = 0
+
+    override fun onViewAttached() {
+        panelExpansionStateManager.addExpansionListener(panelExpansionListener)
+        dialogManager.registerListener(dialogListener)
+        dumpManager.registerDumpable(dumpTag, this)
+    }
+
+    override fun onViewDetached() {
+        panelExpansionStateManager.removeExpansionListener(panelExpansionListener)
+        dialogManager.unregisterListener(dialogListener)
+        dumpManager.unregisterDumpable(dumpTag)
+    }
+
+    /**
+     * in some cases, onViewAttached is called for the newly added view using an instance of
+     * this controller before onViewDetached is called on the previous view, so we must have a
+     * unique [dumpTag] per instance of this class.
+     */
+    private val dumpTag = "$tag ($this)"
+
+    override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<String>) {
+        pw.println("mNotificationShadeVisible=$notificationShadeVisible")
+        pw.println("shouldPauseAuth()=" + shouldPauseAuth())
+        pw.println("isPauseAuth=" + view.isPauseAuth)
+    }
+
+    /**
+     * Returns true if the fingerprint manager is running, but we want to temporarily pause
+     * authentication.
+     */
+    open fun shouldPauseAuth(): Boolean {
+        return notificationShadeVisible || dialogManager.shouldHideAffordance()
+    }
+
+    /**
+     * Send pause auth update to our view.
+     */
+    fun updatePauseAuth() {
+        if (view.setPauseAuth(shouldPauseAuth())) {
+            view.postInvalidate()
+        }
+    }
+
+    /**
+     * Send sensor position change to our view. This rect contains paddingX and paddingY.
+     */
+    fun onSensorRectUpdated(sensorRect: RectF) {
+        view.onSensorRectUpdated(sensorRect)
+    }
+
+    /**
+     * Send dozeTimeTick to view in case it wants to handle its burn-in offset.
+     */
+    fun dozeTimeTick() {
+        if (view.dozeTimeTick()) {
+            view.postInvalidate()
+        }
+    }
+
+    /**
+     * Udfps has started illuminating and the fingerprint manager is working on authenticating.
+     */
+    fun onIlluminationStarting() {
+        view.onIlluminationStarting()
+        view.postInvalidate()
+    }
+
+    /**
+     * Udfps has stopped illuminating and the fingerprint manager is no longer attempting to
+     * authenticate.
+     */
+    fun onIlluminationStopped() {
+        view.onIlluminationStopped()
+        view.postInvalidate()
+    }
+
+    /**
+     * Whether to listen for touches outside of the view.
+     */
+    open fun listenForTouchesOutsideView(): Boolean = false
+
+    /**
+     * Called on touches outside of the view if listenForTouchesOutsideView returns true
+     */
+    open fun onTouchOutsideView() {}
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpView.java
deleted file mode 100644
index 70be907..0000000
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpView.java
+++ /dev/null
@@ -1,45 +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.biometrics;
-
-import android.content.Context;
-import android.util.AttributeSet;
-
-import androidx.annotation.Nullable;
-
-/**
- * Class that coordinates non-HBM animations during BiometricPrompt.
- *
- * Currently doesn't draw anything.
- *
- * Note that {@link AuthBiometricUdfpsView} also shows UDFPS animations. At some point we should
- * de-dupe this if necessary.
- */
-public class UdfpsBpView extends UdfpsAnimationView {
-    private UdfpsFpDrawable mFingerprintDrawable;
-
-    public UdfpsBpView(Context context, @Nullable AttributeSet attrs) {
-        super(context, attrs);
-        // Drawable isn't ever added to the view, so we don't currently show anything
-        mFingerprintDrawable = new UdfpsFpDrawable(mContext);
-    }
-
-    @Override
-    UdfpsDrawable getDrawable() {
-        return mFingerprintDrawable;
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpView.kt
new file mode 100644
index 0000000..6607915
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpView.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.systemui.biometrics
+
+import android.content.Context
+import android.util.AttributeSet
+
+/**
+ * Class that coordinates non-HBM animations during BiometricPrompt.
+ *
+ * Currently doesn't draw anything.
+ *
+ * Note that [AuthBiometricUdfpsView] also shows UDFPS animations. At some point we should
+ * de-dupe this if necessary.
+ */
+class UdfpsBpView(context: Context, attrs: AttributeSet?) : UdfpsAnimationView(context, attrs) {
+
+    // Drawable isn't ever added to the view, so we don't currently show anything
+    private val fingerprintDrawable: UdfpsFpDrawable = UdfpsFpDrawable(context)
+
+    override fun getDrawable(): UdfpsDrawable = fingerprintDrawable
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpViewController.java
deleted file mode 100644
index 3732100..0000000
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpViewController.java
+++ /dev/null
@@ -1,44 +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.biometrics;
-
-import android.annotation.NonNull;
-
-import com.android.systemui.dump.DumpManager;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.phone.SystemUIDialogManager;
-import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
-
-/**
- * Class that coordinates non-HBM animations for biometric prompt.
- */
-class UdfpsBpViewController extends UdfpsAnimationViewController<UdfpsBpView> {
-    protected UdfpsBpViewController(
-            @NonNull UdfpsBpView view,
-            @NonNull StatusBarStateController statusBarStateController,
-            @NonNull PanelExpansionStateManager panelExpansionStateManager,
-            @NonNull SystemUIDialogManager systemUIDialogManager,
-            @NonNull DumpManager dumpManager) {
-        super(view, statusBarStateController, panelExpansionStateManager,
-                systemUIDialogManager, dumpManager);
-    }
-
-    @Override
-    @NonNull String getTag() {
-        return "UdfpsBpViewController";
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpViewController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpViewController.kt
new file mode 100644
index 0000000..4cd40d2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpViewController.kt
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.biometrics
+
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.statusbar.phone.SystemUIDialogManager
+import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager
+
+/**
+ * Class that coordinates non-HBM animations for biometric prompt.
+ */
+class UdfpsBpViewController(
+    view: UdfpsBpView,
+    statusBarStateController: StatusBarStateController,
+    panelExpansionStateManager: PanelExpansionStateManager,
+    systemUIDialogManager: SystemUIDialogManager,
+    dumpManager: DumpManager
+) : UdfpsAnimationViewController<UdfpsBpView>(
+    view,
+    statusBarStateController,
+    panelExpansionStateManager,
+    systemUIDialogManager,
+    dumpManager
+) {
+    override val tag = "UdfpsBpViewController"
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index 1da9f21..fd7ae32 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -24,15 +24,11 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.SuppressLint;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.graphics.PixelFormat;
-import android.graphics.Point;
 import android.graphics.RectF;
-import android.hardware.biometrics.BiometricOverlayConstants;
 import android.hardware.biometrics.SensorLocationInternal;
 import android.hardware.display.DisplayManager;
 import android.hardware.fingerprint.FingerprintManager;
@@ -42,24 +38,21 @@
 import android.os.Handler;
 import android.os.PowerManager;
 import android.os.Process;
-import android.os.RemoteException;
 import android.os.Trace;
 import android.os.VibrationAttributes;
 import android.os.VibrationEffect;
 import android.os.Vibrator;
 import android.util.Log;
-import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
-import android.view.Surface;
 import android.view.VelocityTracker;
 import android.view.View;
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityManager;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.LatencyTracker;
 import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.systemui.R;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.doze.DozeReceiver;
@@ -95,7 +88,7 @@
  * controls/manages all UDFPS sensors. In other words, a single controller is registered with
  * {@link com.android.server.biometrics.sensors.fingerprint.FingerprintService}, and interfaces such
  * as {@link FingerprintManager#onPointerDown(int, int, int, float, float)} or
- * {@link IUdfpsOverlayController#showUdfpsOverlay(int)} should all have
+ * {@link IUdfpsOverlayController#showUdfpsOverlay} should all have
  * {@code sensorId} parameters.
  */
 @SuppressWarnings("deprecation")
@@ -132,11 +125,11 @@
     @NonNull private final SystemClock mSystemClock;
     @NonNull private final UnlockedScreenOffAnimationController
             mUnlockedScreenOffAnimationController;
+    @NonNull private final LatencyTracker mLatencyTracker;
     @VisibleForTesting @NonNull final BiometricDisplayListener 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.
     @VisibleForTesting final FingerprintSensorPropertiesInternal mSensorProps;
-    private final WindowManager.LayoutParams mCoreLayoutParams;
 
     // Tracks the velocity of a touch to help filter out the touches that move too fast.
     @Nullable private VelocityTracker mVelocityTracker;
@@ -150,9 +143,8 @@
     // TODO: We should probably try to make touch/illumination things more of a FSM
     private boolean mGoodCaptureReceived;
 
-    @Nullable private UdfpsView mView;
     // The current request from FingerprintService. Null if no current request.
-    @Nullable ServerRequest mServerRequest;
+    @Nullable UdfpsControllerOverlay mOverlay;
 
     // The fingerprint AOD trigger doesn't provide an ACTION_UP/ACTION_CANCEL event to tell us when
     // to turn off high brightness mode. To get around this limitation, the state of the AOD
@@ -164,7 +156,7 @@
     private Runnable mAodInterruptRunnable;
     private boolean mOnFingerDown;
     private boolean mAttemptedToDismissKeyguard;
-    private Set<Callback> mCallbacks = new HashSet<>();
+    private final Set<Callback> mCallbacks = new HashSet<>();
 
     @VisibleForTesting
     public static final VibrationAttributes VIBRATION_ATTRIBUTES =
@@ -193,67 +185,20 @@
         }
     };
 
-    /**
-     * Keeps track of state within a single FingerprintService request. Note that this state
-     * persists across configuration changes, etc, since it is considered a single request.
-     *
-     * TODO: Perhaps we can move more global variables into here
-     */
-    private static class ServerRequest {
-        // Reason the overlay has been requested. See IUdfpsOverlayController for definitions.
-        final int mRequestReason;
-        @NonNull final IUdfpsOverlayControllerCallback mCallback;
-        @Nullable final UdfpsEnrollHelper mEnrollHelper;
-
-        ServerRequest(int requestReason, @NonNull IUdfpsOverlayControllerCallback callback,
-                @Nullable UdfpsEnrollHelper enrollHelper) {
-            mRequestReason = requestReason;
-            mCallback = callback;
-            mEnrollHelper = enrollHelper;
-        }
-
-        void onEnrollmentProgress(int remaining) {
-            if (mEnrollHelper != null) {
-                mEnrollHelper.onEnrollmentProgress(remaining);
-            }
-        }
-
-        void onAcquiredGood() {
-            if (mEnrollHelper != null) {
-                mEnrollHelper.animateIfLastStep();
-            }
-        }
-
-        void onEnrollmentHelp() {
-            if (mEnrollHelper != null) {
-                mEnrollHelper.onEnrollmentHelp();
-            }
-        }
-
-        void onUserCanceled() {
-            try {
-                mCallback.onUserCanceled();
-            } catch (RemoteException e) {
-                Log.e(TAG, "Remote exception", e);
-            }
-        }
-    }
-
     public class UdfpsOverlayController extends IUdfpsOverlayController.Stub {
         @Override
         public void showUdfpsOverlay(int sensorId, int reason,
                 @NonNull IUdfpsOverlayControllerCallback callback) {
-            mFgExecutor.execute(() -> {
-                final UdfpsEnrollHelper enrollHelper;
-                if (reason == BiometricOverlayConstants.REASON_ENROLL_FIND_SENSOR
-                        || reason == BiometricOverlayConstants.REASON_ENROLL_ENROLLING) {
-                    enrollHelper = new UdfpsEnrollHelper(mContext, mFingerprintManager, reason);
-                } else {
-                    enrollHelper = null;
-                }
-                mServerRequest = new ServerRequest(reason, callback, enrollHelper);
-                updateOverlay();
-            });
+            mFgExecutor.execute(
+                    () -> UdfpsController.this.showUdfpsOverlay(new UdfpsControllerOverlay(
+                            mContext, mFingerprintManager, mInflater, mWindowManager,
+                            mAccessibilityManager, mStatusBarStateController,
+                            mPanelExpansionStateManager, mKeyguardViewManager,
+                            mKeyguardUpdateMonitor, mDialogManager, mDumpManager,
+                            mLockscreenShadeTransitionController, mConfigurationController,
+                            mSystemClock, mKeyguardStateController,
+                            mUnlockedScreenOffAnimationController, mSensorProps, mHbmProvider,
+                            reason, callback, UdfpsController.this::onTouch)));
         }
 
         @Override
@@ -266,57 +211,55 @@
                             + "mKeyguardUpdateMonitor.isFingerprintDetectionRunning()=true");
                 }
 
-                mServerRequest = null;
-                updateOverlay();
+                UdfpsController.this.hideUdfpsOverlay();
             });
         }
 
         @Override
         public void onAcquiredGood(int sensorId) {
             mFgExecutor.execute(() -> {
-                if (mView == null) {
-                    Log.e(TAG, "Null view when onAcquiredGood for sensorId: " + sensorId);
+                if (mOverlay == null) {
+                    Log.e(TAG, "Null request when onAcquiredGood for sensorId: " + sensorId);
                     return;
                 }
                 mGoodCaptureReceived = true;
-                mView.stopIllumination();
-                if (mServerRequest != null) {
-                    mServerRequest.onAcquiredGood();
-                } else {
-                    Log.e(TAG, "Null serverRequest when onAcquiredGood");
+                final UdfpsView view = mOverlay.getOverlayView();
+                if (view != null) {
+                    view.stopIllumination();
                 }
+                mOverlay.onAcquiredGood();
             });
         }
 
         @Override
         public void onEnrollmentProgress(int sensorId, int remaining) {
             mFgExecutor.execute(() -> {
-                if (mServerRequest == null) {
+                if (mOverlay == null) {
                     Log.e(TAG, "onEnrollProgress received but serverRequest is null");
                     return;
                 }
-                mServerRequest.onEnrollmentProgress(remaining);
+                mOverlay.onEnrollmentProgress(remaining);
             });
         }
 
         @Override
         public void onEnrollmentHelp(int sensorId) {
             mFgExecutor.execute(() -> {
-                if (mServerRequest == null) {
+                if (mOverlay == null) {
                     Log.e(TAG, "onEnrollmentHelp received but serverRequest is null");
                     return;
                 }
-                mServerRequest.onEnrollmentHelp();
+                mOverlay.onEnrollmentHelp();
             });
         }
 
         @Override
         public void setDebugMessage(int sensorId, String message) {
             mFgExecutor.execute(() -> {
-                if (mView == null) {
+                if (mOverlay == null || mOverlay.isHiding()) {
                     return;
                 }
-                mView.setDebugMessage(message);
+                mOverlay.getOverlayView().setDebugMessage(message);
             });
         }
     }
@@ -341,14 +284,13 @@
     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
-            if (mServerRequest != null
-                    && mServerRequest.mRequestReason != REASON_AUTH_KEYGUARD
+            if (mOverlay != null
+                    && mOverlay.getRequestReason() != REASON_AUTH_KEYGUARD
                     && Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) {
                 Log.d(TAG, "ACTION_CLOSE_SYSTEM_DIALOGS received, mRequestReason: "
-                        + mServerRequest.mRequestReason);
-                mServerRequest.onUserCanceled();
-                mServerRequest = null;
-                updateOverlay();
+                        + mOverlay.getRequestReason());
+                mOverlay.cancel();
+                hideUdfpsOverlay();
             }
         }
     };
@@ -357,23 +299,12 @@
      * Forwards touches to the udfps controller / view
      */
     public boolean onTouch(MotionEvent event) {
-        if (mView == null) {
+        if (mOverlay == null || mOverlay.isHiding()) {
             return false;
         }
-        return onTouch(mView, event, false);
+        return onTouch(mOverlay.getOverlayView(), event, false);
     }
 
-    @SuppressLint("ClickableViewAccessibility")
-    private final UdfpsView.OnTouchListener mOnTouchListener = (view, event) ->
-            onTouch(view, event, true);
-
-    @SuppressLint("ClickableViewAccessibility")
-    private final UdfpsView.OnHoverListener mOnHoverListener = (view, event) ->
-            onTouch(view, event, true);
-
-    private final AccessibilityManager.TouchExplorationStateChangeListener
-            mTouchExplorationStateChangeListener = enabled -> updateTouchListener();
-
     /**
      * @param x coordinate
      * @param y coordinate
@@ -387,15 +318,15 @@
             return udfpsView.isWithinSensorArea(x, y);
         }
 
-        if (mView == null || mView.getAnimationViewController() == null) {
+        if (mOverlay == null || mOverlay.getAnimationViewController() == null) {
             return false;
         }
 
-        return !mView.getAnimationViewController().shouldPauseAuth()
+        return !mOverlay.getAnimationViewController().shouldPauseAuth()
                 && getSensorLocation().contains(x, y);
     }
 
-    private boolean onTouch(View view, MotionEvent event, boolean fromUdfpsView) {
+    private boolean onTouch(@NonNull View view, @NonNull MotionEvent event, boolean fromUdfpsView) {
         UdfpsView udfpsView = (UdfpsView) view;
         final boolean isIlluminationRequested = udfpsView.isIlluminationRequested();
         boolean handled = false;
@@ -419,6 +350,7 @@
                 boolean withinSensorArea =
                         isWithinSensorArea(udfpsView, event.getX(), event.getY(), fromUdfpsView);
                 if (withinSensorArea) {
+                    mLatencyTracker.onActionStart(LatencyTracker.ACTION_UDFPS_ILLUMINATE);
                     Trace.beginAsyncSection("UdfpsController.e2e.onPointerDown", 0);
                     Log.v(TAG, "onTouch | action down");
                     // The pointer that causes ACTION_DOWN is always at index 0.
@@ -492,7 +424,7 @@
                         }
                     } else {
                         Log.v(TAG, "onTouch | finger outside");
-                        onFingerUp();
+                        onFingerUp(udfpsView);
                     }
                 }
                 Trace.endSection();
@@ -509,7 +441,7 @@
                 }
                 Log.v(TAG, "onTouch | finger up");
                 mAttemptedToDismissKeyguard = false;
-                onFingerUp();
+                onFingerUp(udfpsView);
                 mFalsingManager.isFalseTouch(UDFPS_AUTHENTICATION);
                 Trace.endSection();
                 break;
@@ -521,8 +453,8 @@
     }
 
     private boolean shouldTryToDismissKeyguard() {
-        return mView.getAnimationViewController() != null
-                && mView.getAnimationViewController() instanceof UdfpsKeyguardViewController
+        return mOverlay != null
+                && mOverlay.getAnimationViewController() instanceof UdfpsKeyguardViewController
                 && mKeyguardStateController.canDismissLockScreen()
                 && !mAttemptedToDismissKeyguard;
     }
@@ -554,7 +486,8 @@
             @NonNull ConfigurationController configurationController,
             @NonNull SystemClock systemClock,
             @NonNull UnlockedScreenOffAnimationController unlockedScreenOffAnimationController,
-            @NonNull SystemUIDialogManager dialogManager) {
+            @NonNull SystemUIDialogManager dialogManager,
+            @NonNull LatencyTracker latencyTracker) {
         mContext = context;
         mExecution = execution;
         mVibrator = vibrator;
@@ -582,6 +515,7 @@
         mConfigurationController = configurationController;
         mSystemClock = systemClock;
         mUnlockedScreenOffAnimationController = unlockedScreenOffAnimationController;
+        mLatencyTracker = latencyTracker;
 
         mSensorProps = findFirstUdfps();
         // At least one UDFPS sensor exists
@@ -596,17 +530,6 @@
                     return Unit.INSTANCE;
                 });
 
-        mCoreLayoutParams = new WindowManager.LayoutParams(
-                WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG,
-                0 /* flags set in computeLayoutParams() */,
-                PixelFormat.TRANSLUCENT);
-        mCoreLayoutParams.setTitle(TAG);
-        mCoreLayoutParams.setFitInsetsTypes(0);
-        mCoreLayoutParams.gravity = Gravity.TOP | Gravity.LEFT;
-        mCoreLayoutParams.layoutInDisplayCutoutMode =
-                WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
-        mCoreLayoutParams.privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
-
         mFingerprintManager.setUdfpsOverlayController(new UdfpsOverlayController());
 
         final IntentFilter filter = new IntentFilter();
@@ -644,8 +567,11 @@
 
     @Override
     public void dozeTimeTick() {
-        if (mView != null) {
-            mView.dozeTimeTick();
+        if (mOverlay != null) {
+            final UdfpsView view = mOverlay.getOverlayView();
+            if (view != null) {
+                view.dozeTimeTick();
+            }
         }
     }
 
@@ -664,233 +590,63 @@
                 location.sensorLocationY + location.sensorRadius);
     }
 
-    private void updateOverlay() {
-        mExecution.assertIsMainThread();
-
-        if (mServerRequest != null) {
-            showUdfpsOverlay(mServerRequest);
-        } else {
+    private void redrawOverlay() {
+        UdfpsControllerOverlay overlay = mOverlay;
+        if (overlay != null) {
             hideUdfpsOverlay();
+            showUdfpsOverlay(overlay);
         }
     }
 
-    private boolean shouldRotate(@Nullable UdfpsAnimationViewController animation) {
-        if (!(animation instanceof UdfpsKeyguardViewController)) {
-            // always rotate view if we're not on the keyguard
-            return true;
-        }
-
-        // on the keyguard, make sure we don't rotate if we're going to sleep or not occluded
-        if (mKeyguardUpdateMonitor.isGoingToSleep() || !mKeyguardStateController.isOccluded()) {
-            return false;
-        }
-
-        return true;
-    }
-
-    private WindowManager.LayoutParams computeLayoutParams(
-            @Nullable UdfpsAnimationViewController animation) {
-        final int paddingX = animation != null ? animation.getPaddingX() : 0;
-        final int paddingY = animation != null ? animation.getPaddingY() : 0;
-
-        mCoreLayoutParams.flags = Utils.FINGERPRINT_OVERLAY_LAYOUT_PARAM_FLAGS
-                | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
-        if (animation != null && animation.listenForTouchesOutsideView()) {
-            mCoreLayoutParams.flags |= WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
-        }
-
-        // Default dimensions assume portrait mode.
-        final SensorLocationInternal location = mSensorProps.getLocation();
-        mCoreLayoutParams.x = location.sensorLocationX - location.sensorRadius - paddingX;
-        mCoreLayoutParams.y = location.sensorLocationY - location.sensorRadius - paddingY;
-        mCoreLayoutParams.height = 2 * location.sensorRadius + 2 * paddingX;
-        mCoreLayoutParams.width = 2 * location.sensorRadius + 2 * paddingY;
-
-        Point p = new Point();
-        // Gets the size based on the current rotation of the display.
-        mContext.getDisplay().getRealSize(p);
-
-        // Transform dimensions if the device is in landscape mode
-        switch (mContext.getDisplay().getRotation()) {
-            case Surface.ROTATION_90:
-                if (!shouldRotate(animation)) {
-                    Log.v(TAG, "skip rotating udfps location ROTATION_90");
-                    break;
-                } else {
-                    Log.v(TAG, "rotate udfps location ROTATION_90");
-                }
-                mCoreLayoutParams.x = location.sensorLocationY - location.sensorRadius
-                        - paddingX;
-                mCoreLayoutParams.y = p.y - location.sensorLocationX - location.sensorRadius
-                        - paddingY;
-                break;
-
-            case Surface.ROTATION_270:
-                if (!shouldRotate(animation)) {
-                    Log.v(TAG, "skip rotating udfps location ROTATION_270");
-                    break;
-                } else {
-                    Log.v(TAG, "rotate udfps location ROTATION_270");
-                }
-                mCoreLayoutParams.x = p.x - location.sensorLocationY - location.sensorRadius
-                        - paddingX;
-                mCoreLayoutParams.y = location.sensorLocationX - location.sensorRadius
-                        - paddingY;
-                break;
-
-            default:
-                // Do nothing to stay in portrait mode.
-                // Keyguard is always in portrait mode.
-        }
-        // avoid announcing window title
-        mCoreLayoutParams.accessibilityTitle = " ";
-        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();
+        redrawOverlay();
         if (wasShowingAltAuth) {
             mKeyguardViewManager.showGenericBouncer(true);
         }
     }
 
-    private void showUdfpsOverlay(@NonNull ServerRequest request) {
+    private void showUdfpsOverlay(@NonNull UdfpsControllerOverlay overlay) {
         mExecution.assertIsMainThread();
 
-        final int reason = request.mRequestReason;
-        if (mView == null) {
-            try {
-                Log.v(TAG, "showUdfpsOverlay | adding window reason=" + reason);
-
-                mView = (UdfpsView) mInflater.inflate(R.layout.udfps_view, null, false);
-                mOnFingerDown = false;
-                mView.setSensorProperties(mSensorProps);
-                mView.setHbmProvider(mHbmProvider);
-                UdfpsAnimationViewController<?> animation = inflateUdfpsAnimation(reason);
-                mAttemptedToDismissKeyguard = false;
-                if (animation != null) {
-                    animation.init();
-                    mView.setAnimationViewController(animation);
-                }
-                mOrientationListener.enable();
-
-                // This view overlaps the sensor area, so prevent it from being selectable
-                // during a11y.
-                if (reason == BiometricOverlayConstants.REASON_ENROLL_FIND_SENSOR
-                        || reason == BiometricOverlayConstants.REASON_ENROLL_ENROLLING
-                        || reason == BiometricOverlayConstants.REASON_AUTH_BP) {
-                    mView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
-                }
-
-                mWindowManager.addView(mView, computeLayoutParams(animation));
-                mAccessibilityManager.addTouchExplorationStateChangeListener(
-                        mTouchExplorationStateChangeListener);
-                updateTouchListener();
-            } catch (RuntimeException e) {
-                Log.e(TAG, "showUdfpsOverlay | failed to add window", e);
-            }
+        mOverlay = overlay;
+        if (overlay.show(this)) {
+            Log.v(TAG, "showUdfpsOverlay | adding window reason="
+                    + overlay.getRequestReason());
+            mOnFingerDown = false;
+            mAttemptedToDismissKeyguard = false;
+            mOrientationListener.enable();
         } else {
             Log.v(TAG, "showUdfpsOverlay | the overlay is already showing");
         }
     }
 
-    @Nullable
-    private UdfpsAnimationViewController<?> inflateUdfpsAnimation(int reason) {
-        switch (reason) {
-            case BiometricOverlayConstants.REASON_ENROLL_FIND_SENSOR:
-            case BiometricOverlayConstants.REASON_ENROLL_ENROLLING:
-                UdfpsEnrollView enrollView = (UdfpsEnrollView) mInflater.inflate(
-                        R.layout.udfps_enroll_view, null);
-                mView.addView(enrollView);
-                enrollView.updateSensorLocation(mSensorProps);
-                return new UdfpsEnrollViewController(
-                        enrollView,
-                        mServerRequest.mEnrollHelper,
-                        mStatusBarStateController,
-                        mPanelExpansionStateManager,
-                        mDialogManager,
-                        mDumpManager
-                );
-            case BiometricOverlayConstants.REASON_AUTH_KEYGUARD:
-                UdfpsKeyguardView keyguardView = (UdfpsKeyguardView)
-                        mInflater.inflate(R.layout.udfps_keyguard_view, null);
-                mView.addView(keyguardView);
-                return new UdfpsKeyguardViewController(
-                        keyguardView,
-                        mStatusBarStateController,
-                        mPanelExpansionStateManager,
-                        mKeyguardViewManager,
-                        mKeyguardUpdateMonitor,
-                        mDumpManager,
-                        mLockscreenShadeTransitionController,
-                        mConfigurationController,
-                        mSystemClock,
-                        mKeyguardStateController,
-                        mUnlockedScreenOffAnimationController,
-                        mDialogManager,
-                        this
-                );
-            case BiometricOverlayConstants.REASON_AUTH_BP:
-                // note: empty controller, currently shows no visual affordance
-                UdfpsBpView bpView = (UdfpsBpView) mInflater.inflate(R.layout.udfps_bp_view, null);
-                mView.addView(bpView);
-                return new UdfpsBpViewController(
-                        bpView,
-                        mStatusBarStateController,
-                        mPanelExpansionStateManager,
-                        mDialogManager,
-                        mDumpManager
-                );
-            case BiometricOverlayConstants.REASON_AUTH_OTHER:
-            case BiometricOverlayConstants.REASON_AUTH_SETTINGS:
-                UdfpsFpmOtherView authOtherView = (UdfpsFpmOtherView)
-                        mInflater.inflate(R.layout.udfps_fpm_other_view, null);
-                mView.addView(authOtherView);
-                return new UdfpsFpmOtherViewController(
-                        authOtherView,
-                        mStatusBarStateController,
-                        mPanelExpansionStateManager,
-                        mDialogManager,
-                        mDumpManager
-                );
-            default:
-                Log.e(TAG, "Animation for reason " + reason + " not supported yet");
-                return null;
-        }
-    }
-
     private void hideUdfpsOverlay() {
         mExecution.assertIsMainThread();
 
-        if (mView != null) {
-            Log.v(TAG, "hideUdfpsOverlay | removing window");
+        if (mOverlay != null) {
             // 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) {
+            final UdfpsView oldView = mOverlay.getOverlayView();
+            if (oldView != null) {
+                onFingerUp(oldView);
+            }
+            final boolean removed = mOverlay.hide();
+            if (mKeyguardViewManager.isShowingAlternateAuth()) {
                 mKeyguardViewManager.resetAlternateAuth(true);
             }
-            mAccessibilityManager.removeTouchExplorationStateChangeListener(
-                    mTouchExplorationStateChangeListener);
-            mView = null;
+            Log.v(TAG, "hideUdfpsOverlay | removing window: " + removed);
         } else {
             Log.v(TAG, "hideUdfpsOverlay | the overlay is already hidden");
         }
 
+        mOverlay = null;
         mOrientationListener.disable();
     }
 
@@ -954,7 +710,9 @@
      * the user lifts their finger.
      */
     void onCancelUdfps() {
-        onFingerUp();
+        if (mOverlay != null && mOverlay.getOverlayView() != null) {
+            onFingerUp(mOverlay.getOverlayView());
+        }
         if (!mIsAodInterruptActive) {
             return;
         }
@@ -971,12 +729,12 @@
 
     private void onFingerDown(int x, int y, float minor, float major) {
         mExecution.assertIsMainThread();
-        if (mView == null) {
-            Log.w(TAG, "Null view in onFingerDown");
+        if (mOverlay == null) {
+            Log.w(TAG, "Null request in onFingerDown");
             return;
         }
 
-        if (mView.getAnimationViewController() instanceof UdfpsKeyguardViewController
+        if (mOverlay.getAnimationViewController() instanceof UdfpsKeyguardViewController
                 && !mStatusBarStateController.isDozing()) {
             mKeyguardBypassController.setUserHasDeviceEntryIntent(true);
         }
@@ -991,25 +749,26 @@
         mOnFingerDown = true;
         mFingerprintManager.onPointerDown(mSensorProps.sensorId, x, y, minor, major);
         Trace.endAsyncSection("UdfpsController.e2e.onPointerDown", 0);
-        Trace.beginAsyncSection("UdfpsController.e2e.startIllumination", 0);
-        mView.startIllumination(() -> {
-            mFingerprintManager.onUiReady(mSensorProps.sensorId);
-            Trace.endAsyncSection("UdfpsController.e2e.startIllumination", 0);
-        });
+
+        final UdfpsView view = mOverlay.getOverlayView();
+        if (view != null) {
+            Trace.beginAsyncSection("UdfpsController.e2e.startIllumination", 0);
+            view.startIllumination(() -> {
+                mFingerprintManager.onUiReady(mSensorProps.sensorId);
+                mLatencyTracker.onActionEnd(LatencyTracker.ACTION_UDFPS_ILLUMINATE);
+                Trace.endAsyncSection("UdfpsController.e2e.startIllumination", 0);
+            });
+        }
 
         for (Callback cb : mCallbacks) {
             cb.onFingerDown();
         }
     }
 
-    private void onFingerUp() {
+    private void onFingerUp(@NonNull UdfpsView view) {
         mExecution.assertIsMainThread();
         mActivePointerId = -1;
         mGoodCaptureReceived = false;
-        if (mView == null) {
-            Log.w(TAG, "Null view in onFingerUp");
-            return;
-        }
         if (mOnFingerDown) {
             mFingerprintManager.onPointerUp(mSensorProps.sensorId);
             for (Callback cb : mCallbacks) {
@@ -1017,22 +776,8 @@
             }
         }
         mOnFingerDown = false;
-        if (mView.isIlluminationRequested()) {
-            mView.stopIllumination();
-        }
-    }
-
-    private void updateTouchListener() {
-        if (mView == null) {
-            return;
-        }
-
-        if (mAccessibilityManager.isTouchExplorationEnabled()) {
-            mView.setOnHoverListener(mOnHoverListener);
-            mView.setOnTouchListener(null);
-        } else {
-            mView.setOnHoverListener(null);
-            mView.setOnTouchListener(mOnTouchListener);
+        if (view.isIlluminationRequested()) {
+            view.stopIllumination();
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
new file mode 100644
index 0000000..e091250
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
@@ -0,0 +1,354 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.biometrics
+
+import android.annotation.SuppressLint
+import android.annotation.UiThread
+import android.content.Context
+import android.graphics.PixelFormat
+import android.graphics.Point
+import android.hardware.biometrics.BiometricOverlayConstants
+import android.hardware.biometrics.BiometricOverlayConstants.REASON_ENROLL_ENROLLING
+import android.hardware.biometrics.BiometricOverlayConstants.REASON_ENROLL_FIND_SENSOR
+import android.hardware.biometrics.BiometricOverlayConstants.ShowReason
+import android.hardware.biometrics.SensorLocationInternal
+import android.hardware.fingerprint.FingerprintManager
+import android.hardware.fingerprint.FingerprintSensorPropertiesInternal
+import android.hardware.fingerprint.IUdfpsOverlayControllerCallback
+import android.os.RemoteException
+import android.util.Log
+import android.view.LayoutInflater
+import android.view.MotionEvent
+import android.view.Surface
+import android.view.View
+import android.view.WindowManager
+import android.view.accessibility.AccessibilityManager
+import android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener
+import androidx.annotation.LayoutRes
+import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.systemui.R
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.statusbar.LockscreenShadeTransitionController
+import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
+import com.android.systemui.statusbar.phone.SystemUIDialogManager
+import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController
+import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager
+import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.statusbar.policy.KeyguardStateController
+import com.android.systemui.util.time.SystemClock
+
+private const val TAG = "UdfpsControllerOverlay"
+
+/**
+ * Keeps track of the overlay state and UI resources associated with a single FingerprintService
+ * request. This state can persist across configuration changes via the [show] and [hide]
+ * methods.
+ */
+@UiThread
+class UdfpsControllerOverlay(
+    private val context: Context,
+    fingerprintManager: FingerprintManager,
+    private val inflater: LayoutInflater,
+    private val windowManager: WindowManager,
+    private val accessibilityManager: AccessibilityManager,
+    private val statusBarStateController: StatusBarStateController,
+    private val panelExpansionStateManager: PanelExpansionStateManager,
+    private val statusBarKeyguardViewManager: StatusBarKeyguardViewManager,
+    private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
+    private val dialogManager: SystemUIDialogManager,
+    private val dumpManager: DumpManager,
+    private val transitionController: LockscreenShadeTransitionController,
+    private val configurationController: ConfigurationController,
+    private val systemClock: SystemClock,
+    private val keyguardStateController: KeyguardStateController,
+    private val unlockedScreenOffAnimationController: UnlockedScreenOffAnimationController,
+    private val sensorProps: FingerprintSensorPropertiesInternal,
+    private var hbmProvider: UdfpsHbmProvider,
+    @ShowReason val requestReason: Int,
+    private val controllerCallback: IUdfpsOverlayControllerCallback,
+    private val onTouch: (View, MotionEvent, Boolean) -> Boolean
+) {
+    /** The view, when [isShowing], or null. */
+    var overlayView: UdfpsView? = null
+        private set
+
+    private var overlayTouchListener: TouchExplorationStateChangeListener? = null
+
+    private val coreLayoutParams = WindowManager.LayoutParams(
+        WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG,
+        0 /* flags set in computeLayoutParams() */,
+        PixelFormat.TRANSLUCENT
+    ).apply {
+        title = TAG
+        fitInsetsTypes = 0
+        gravity = android.view.Gravity.TOP or android.view.Gravity.LEFT
+        layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
+        privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY
+    }
+
+    /** A helper if the [requestReason] was due to enrollment. */
+    val enrollHelper: UdfpsEnrollHelper? = if (requestReason.isEnrollmentReason()) {
+        UdfpsEnrollHelper(context, fingerprintManager, requestReason)
+    } else {
+        null
+    }
+
+    /** If the overlay is currently showing. */
+    val isShowing: Boolean
+        get() = overlayView != null
+
+    /** Opposite of [isShowing]. */
+    val isHiding: Boolean
+        get() = overlayView == null
+
+    /** The animation controller if the overlay [isShowing]. */
+    val animationViewController: UdfpsAnimationViewController<*>?
+        get() = overlayView?.animationViewController
+
+    /** Show the overlay or return false and do nothing if it is already showing. */
+    @SuppressLint("ClickableViewAccessibility")
+    fun show(controller: UdfpsController): Boolean {
+        if (overlayView == null) {
+            try {
+                overlayView = (inflater.inflate(
+                    R.layout.udfps_view, null, false
+                ) as UdfpsView).apply {
+                    sensorProperties = sensorProps
+                    setHbmProvider(hbmProvider)
+                    val animation = inflateUdfpsAnimation(this, controller)
+                    if (animation != null) {
+                        animation.init()
+                        animationViewController = animation
+                    }
+                    // This view overlaps the sensor area
+                    // prevent it from being selectable during a11y
+                    if (requestReason.isImportantForAccessibility()) {
+                        importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_NO
+                    }
+
+                    windowManager.addView(this,
+                        coreLayoutParams.updateForLocation(sensorProps.location, animation))
+
+                    overlayTouchListener = TouchExplorationStateChangeListener {
+                        if (accessibilityManager.isTouchExplorationEnabled) {
+                            setOnHoverListener { v, event -> onTouch(v, event, true) }
+                            setOnTouchListener(null)
+                        } else {
+                            setOnHoverListener(null)
+                            setOnTouchListener { v, event -> onTouch(v, event, true) }
+                        }
+                    }
+                    accessibilityManager.addTouchExplorationStateChangeListener(
+                        overlayTouchListener!!
+                    )
+                    overlayTouchListener?.onTouchExplorationStateChanged(true)
+                }
+            } catch (e: RuntimeException) {
+                Log.e(TAG, "showUdfpsOverlay | failed to add window", e)
+            }
+            return true
+        }
+
+        Log.v(TAG, "showUdfpsOverlay | the overlay is already showing")
+        return false
+    }
+
+    private fun inflateUdfpsAnimation(
+        view: UdfpsView,
+        controller: UdfpsController
+    ): UdfpsAnimationViewController<*>? {
+        return when (requestReason) {
+            REASON_ENROLL_FIND_SENSOR,
+            REASON_ENROLL_ENROLLING -> {
+                UdfpsEnrollViewController(
+                    view.addUdfpsView(R.layout.udfps_enroll_view) {
+                        updateSensorLocation(sensorProps)
+                    },
+                    enrollHelper ?: throw IllegalStateException("no enrollment helper"),
+                    statusBarStateController,
+                    panelExpansionStateManager,
+                    dialogManager,
+                    dumpManager
+                )
+            }
+            BiometricOverlayConstants.REASON_AUTH_KEYGUARD -> {
+                UdfpsKeyguardViewController(
+                    view.addUdfpsView(R.layout.udfps_keyguard_view),
+                    statusBarStateController,
+                    panelExpansionStateManager,
+                    statusBarKeyguardViewManager,
+                    keyguardUpdateMonitor,
+                    dumpManager,
+                    transitionController,
+                    configurationController,
+                    systemClock,
+                    keyguardStateController,
+                    unlockedScreenOffAnimationController,
+                    dialogManager,
+                    controller
+                )
+            }
+            BiometricOverlayConstants.REASON_AUTH_BP -> {
+                // note: empty controller, currently shows no visual affordance
+                UdfpsBpViewController(
+                    view.addUdfpsView(R.layout.udfps_bp_view),
+                    statusBarStateController,
+                    panelExpansionStateManager,
+                    dialogManager,
+                    dumpManager
+                )
+            }
+            BiometricOverlayConstants.REASON_AUTH_OTHER,
+            BiometricOverlayConstants.REASON_AUTH_SETTINGS -> {
+                UdfpsFpmOtherViewController(
+                    view.addUdfpsView(R.layout.udfps_fpm_other_view),
+                    statusBarStateController,
+                    panelExpansionStateManager,
+                    dialogManager,
+                    dumpManager
+                )
+            }
+            else -> {
+                Log.e(TAG, "Animation for reason $requestReason not supported yet")
+                null
+            }
+        }
+    }
+
+    /** Hide the overlay or return false and do nothing if it is already hidden. */
+    fun hide(): Boolean {
+        val wasShowing = isShowing
+
+        overlayView?.apply {
+            if (isIlluminationRequested) {
+                stopIllumination()
+            }
+            windowManager.removeView(this)
+            setOnTouchListener(null)
+            setOnHoverListener(null)
+            animationViewController = null
+            overlayTouchListener?.let {
+                accessibilityManager.removeTouchExplorationStateChangeListener(it)
+            }
+        }
+        overlayView = null
+        overlayTouchListener = null
+
+        return wasShowing
+    }
+
+    fun onEnrollmentProgress(remaining: Int) {
+        enrollHelper?.onEnrollmentProgress(remaining)
+    }
+
+    fun onAcquiredGood() {
+        enrollHelper?.animateIfLastStep()
+    }
+
+    fun onEnrollmentHelp() {
+        enrollHelper?.onEnrollmentHelp()
+    }
+
+    /** Cancel this request. */
+    fun cancel() {
+        try {
+            controllerCallback.onUserCanceled()
+        } catch (e: RemoteException) {
+            Log.e(TAG, "Remote exception", e)
+        }
+    }
+
+    private fun WindowManager.LayoutParams.updateForLocation(
+        location: SensorLocationInternal,
+        animation: UdfpsAnimationViewController<*>?
+    ): WindowManager.LayoutParams {
+        val paddingX = animation?.paddingX ?: 0
+        val paddingY = animation?.paddingY ?: 0
+        flags = (Utils.FINGERPRINT_OVERLAY_LAYOUT_PARAM_FLAGS
+            or WindowManager.LayoutParams.FLAG_SPLIT_TOUCH)
+        if (animation != null && animation.listenForTouchesOutsideView()) {
+            flags = flags or WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
+        }
+
+        // Default dimensions assume portrait mode.
+        x = location.sensorLocationX - location.sensorRadius - paddingX
+        y = location.sensorLocationY - location.sensorRadius - paddingY
+        height = 2 * location.sensorRadius + 2 * paddingX
+        width = 2 * location.sensorRadius + 2 * paddingY
+
+        // Gets the size based on the current rotation of the display.
+        val p = Point()
+        context.display!!.getRealSize(p)
+        when (context.display!!.rotation) {
+            Surface.ROTATION_90 -> {
+                if (!shouldRotate(animation)) {
+                    Log.v(TAG, "skip rotating udfps location ROTATION_90")
+                } else {
+                    Log.v(TAG, "rotate udfps location ROTATION_90")
+                    x = (location.sensorLocationY - location.sensorRadius - paddingX)
+                    y = (p.y - location.sensorLocationX - location.sensorRadius - paddingY)
+                }
+            }
+            Surface.ROTATION_270 -> {
+                if (!shouldRotate(animation)) {
+                    Log.v(TAG, "skip rotating udfps location ROTATION_270")
+                } else {
+                    Log.v(TAG, "rotate udfps location ROTATION_270")
+                    x = (p.x - location.sensorLocationY - location.sensorRadius - paddingX)
+                    y = (location.sensorLocationX - location.sensorRadius - paddingY)
+                }
+            }
+            else -> {}
+        }
+
+        // avoid announcing window title
+        accessibilityTitle = " "
+
+        return this
+    }
+
+    private fun shouldRotate(animation: UdfpsAnimationViewController<*>?): Boolean {
+        if (animation !is UdfpsKeyguardViewController) {
+            // always rotate view if we're not on the keyguard
+            return true
+        }
+
+        // on the keyguard, make sure we don't rotate if we're going to sleep or not occluded
+        return !(keyguardUpdateMonitor.isGoingToSleep || !keyguardStateController.isOccluded)
+    }
+
+    private inline fun <reified T : View> UdfpsView.addUdfpsView(
+        @LayoutRes id: Int,
+        init: T.() -> Unit = {}
+    ): T {
+        val subView = inflater.inflate(id, null) as T
+        addView(subView)
+        subView.init()
+        return subView
+    }
+}
+
+@ShowReason
+private fun Int.isEnrollmentReason() =
+    this == REASON_ENROLL_FIND_SENSOR || this == REASON_ENROLL_ENROLLING
+
+@ShowReason
+private fun Int.isImportantForAccessibility() =
+    this == REASON_ENROLL_FIND_SENSOR ||
+        this == REASON_ENROLL_ENROLLING ||
+        this == BiometricOverlayConstants.REASON_AUTH_BP
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDrawable.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDrawable.java
deleted file mode 100644
index 55ed5aa..0000000
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDrawable.java
+++ /dev/null
@@ -1,113 +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.biometrics;
-
-import android.content.Context;
-import android.graphics.ColorFilter;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.graphics.RectF;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.ShapeDrawable;
-import android.graphics.drawable.shapes.PathShape;
-import android.util.PathParser;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import com.android.systemui.R;
-
-/**
- * Abstract base class for drawable displayed when the finger is not touching the
- * sensor area.
- */
-public abstract class UdfpsDrawable extends Drawable {
-    static final float DEFAULT_STROKE_WIDTH = 3f;
-
-    @NonNull final Context mContext;
-    @NonNull final ShapeDrawable mFingerprintDrawable;
-    private final Paint mPaint;
-    private boolean mIlluminationShowing;
-
-    int mAlpha = 255; // 0 - 255
-    public UdfpsDrawable(@NonNull Context context) {
-        mContext = context;
-        final String fpPath = context.getResources().getString(R.string.config_udfpsIcon);
-        mFingerprintDrawable = new ShapeDrawable(
-                new PathShape(PathParser.createPathFromPathData(fpPath), 72, 72));
-        mFingerprintDrawable.mutate();
-
-        mPaint = mFingerprintDrawable.getPaint();
-        mPaint.setStyle(Paint.Style.STROKE);
-        mPaint.setStrokeCap(Paint.Cap.ROUND);
-        setStrokeWidth(DEFAULT_STROKE_WIDTH);
-    }
-
-    void setStrokeWidth(float strokeWidth) {
-        mPaint.setStrokeWidth(strokeWidth);
-        invalidateSelf();
-    }
-
-    /**
-     * @param sensorRect the rect coordinates for the sensor area
-     */
-    public void onSensorRectUpdated(@NonNull RectF sensorRect) {
-        final int margin =  (int) sensorRect.height() / 8;
-
-        final Rect bounds = new Rect((int) sensorRect.left + margin,
-                (int) sensorRect.top + margin,
-                (int) sensorRect.right - margin,
-                (int) sensorRect.bottom - margin);
-        updateFingerprintIconBounds(bounds);
-    }
-
-    /**
-     * Bounds for the fingerprint icon
-     */
-    protected void updateFingerprintIconBounds(@NonNull Rect bounds) {
-        mFingerprintDrawable.setBounds(bounds);
-        invalidateSelf();
-    }
-
-    @Override
-    public void setAlpha(int alpha) {
-        mAlpha = alpha;
-        mFingerprintDrawable.setAlpha(mAlpha);
-        invalidateSelf();
-    }
-
-    boolean isIlluminationShowing() {
-        return mIlluminationShowing;
-    }
-
-    void setIlluminationShowing(boolean showing) {
-        if (mIlluminationShowing == showing) {
-            return;
-        }
-        mIlluminationShowing = showing;
-        invalidateSelf();
-    }
-
-    @Override
-    public void setColorFilter(@Nullable ColorFilter colorFilter) {
-    }
-
-    @Override
-    public int getOpacity() {
-        return 0;
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDrawable.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDrawable.kt
new file mode 100644
index 0000000..ee112b4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDrawable.kt
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.biometrics
+
+import android.content.Context
+import android.graphics.ColorFilter
+import android.graphics.Paint
+import android.graphics.Rect
+import android.graphics.RectF
+import android.graphics.drawable.Drawable
+import android.graphics.drawable.ShapeDrawable
+import android.graphics.drawable.shapes.PathShape
+import android.util.PathParser
+import com.android.systemui.R
+
+private const val DEFAULT_STROKE_WIDTH = 3f
+
+/**
+ * Abstract base class for drawable displayed when the finger is not touching the
+ * sensor area.
+ */
+abstract class UdfpsDrawable(
+    protected val context: Context,
+    drawableFactory: (Context) -> ShapeDrawable
+) : Drawable() {
+
+    constructor(context: Context) : this(context, defaultFactory)
+
+    /** Fingerprint affordance. */
+    val fingerprintDrawable: ShapeDrawable = drawableFactory(context)
+
+    private var _alpha: Int = 255 // 0 - 255
+
+    var strokeWidth: Float = fingerprintDrawable.paint.strokeWidth
+        set(value) {
+            field = value
+            fingerprintDrawable.paint.strokeWidth = value
+            invalidateSelf()
+        }
+
+    var isIlluminationShowing: Boolean = false
+        set(showing) {
+            if (field == showing) {
+                return
+            }
+            field = showing
+            invalidateSelf()
+        }
+
+    /** The [sensorRect] coordinates for the sensor area. */
+    open fun onSensorRectUpdated(sensorRect: RectF) {
+        val margin = sensorRect.height().toInt() / 8
+        val bounds = Rect(
+            sensorRect.left.toInt() + margin,
+            sensorRect.top.toInt() + margin,
+            sensorRect.right.toInt() - margin,
+            sensorRect.bottom.toInt() - margin
+        )
+        updateFingerprintIconBounds(bounds)
+    }
+
+    /** Bounds for the fingerprint icon. */
+    protected open fun updateFingerprintIconBounds(bounds: Rect) {
+        fingerprintDrawable.bounds = bounds
+        invalidateSelf()
+    }
+
+    override fun getAlpha(): Int = _alpha
+
+    override fun setAlpha(alpha: Int) {
+        _alpha = alpha
+        fingerprintDrawable.alpha = alpha
+        invalidateSelf()
+    }
+
+    override fun setColorFilter(colorFilter: ColorFilter?) {}
+
+    override fun getOpacity(): Int = 0
+}
+
+private val defaultFactory = { context: Context ->
+    val fpPath = context.resources.getString(R.string.config_udfpsIcon)
+    val drawable = ShapeDrawable(
+        PathShape(PathParser.createPathFromPathData(fpPath), 72f, 72f)
+    )
+    drawable.mutate()
+    drawable.paint.style = Paint.Style.STROKE
+    drawable.paint.strokeCap = Paint.Cap.ROUND
+    drawable.paint.strokeWidth = DEFAULT_STROKE_WIDTH
+    drawable
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java
index ac38b13..e701511 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java
@@ -102,7 +102,7 @@
 
         mSensorOutlinePaint = new Paint(0 /* flags */);
         mSensorOutlinePaint.setAntiAlias(true);
-        mSensorOutlinePaint.setColor(mContext.getColor(R.color.udfps_moving_target_fill));
+        mSensorOutlinePaint.setColor(context.getColor(R.color.udfps_moving_target_fill));
         mSensorOutlinePaint.setStyle(Paint.Style.FILL);
 
         mBlueFill = new Paint(0 /* flags */);
@@ -112,10 +112,10 @@
 
         mMovingTargetFpIcon = context.getResources()
                 .getDrawable(R.drawable.ic_kg_fingerprint, null);
-        mMovingTargetFpIcon.setTint(mContext.getColor(R.color.udfps_enroll_icon));
+        mMovingTargetFpIcon.setTint(context.getColor(R.color.udfps_enroll_icon));
         mMovingTargetFpIcon.mutate();
 
-        mFingerprintDrawable.setTint(mContext.getColor(R.color.udfps_enroll_icon));
+        getFingerprintDrawable().setTint(context.getColor(R.color.udfps_enroll_icon));
 
         mHintColorFaded = context.getColor(R.color.udfps_moving_target_fill);
         mHintColorHighlight = context.getColor(R.color.udfps_enroll_progress);
@@ -404,9 +404,9 @@
             if (mSensorRect != null) {
                 canvas.drawOval(mSensorRect, mSensorOutlinePaint);
             }
-            mFingerprintDrawable.draw(canvas);
-            mFingerprintDrawable.setAlpha(mAlpha);
-            mSensorOutlinePaint.setAlpha(mAlpha);
+            getFingerprintDrawable().draw(canvas);
+            getFingerprintDrawable().setAlpha(getAlpha());
+            mSensorOutlinePaint.setAlpha(getAlpha());
         }
 
         // Draw the finger tip or edges hint.
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java
index ac9e92e..2ca103b 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java
@@ -66,7 +66,7 @@
     }
 
     @Override
-    @NonNull String getTag() {
+    @NonNull protected String getTag() {
         return "UdfpsEnrollViewController";
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpDrawable.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpDrawable.kt
similarity index 61%
copy from packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpDrawable.java
copy to packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpDrawable.kt
index 09b6fab..1afa36b 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpDrawable.kt
@@ -13,29 +13,19 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package com.android.systemui.biometrics
 
-package com.android.systemui.biometrics;
-
-import android.content.Context;
-import android.graphics.Canvas;
-
-import androidx.annotation.NonNull;
+import android.content.Context
+import android.graphics.Canvas
 
 /**
  * Draws udfps fingerprint if sensor isn't illuminating.
  */
-public class UdfpsFpDrawable extends UdfpsDrawable {
-
-    UdfpsFpDrawable(@NonNull Context context) {
-        super(context);
-    }
-
-    @Override
-    public void draw(@NonNull Canvas canvas) {
-        if (isIlluminationShowing()) {
-            return;
+class UdfpsFpDrawable(context: Context) : UdfpsDrawable(context) {
+    override fun draw(canvas: Canvas) {
+        if (isIlluminationShowing) {
+            return
         }
-
-        mFingerprintDrawable.draw(canvas);
+        fingerprintDrawable.draw(canvas)
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherView.java
deleted file mode 100644
index 85f1606..0000000
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherView.java
+++ /dev/null
@@ -1,49 +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.biometrics;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.widget.ImageView;
-
-import androidx.annotation.Nullable;
-
-import com.android.systemui.R;
-
-/**
- * View corresponding with udfps_fpm_other_view.xml
- */
-public class UdfpsFpmOtherView extends UdfpsAnimationView {
-    private final UdfpsFpDrawable mFingerprintDrawable;
-    private ImageView mFingerprintView;
-
-    public UdfpsFpmOtherView(Context context, @Nullable AttributeSet attrs) {
-        super(context, attrs);
-        mFingerprintDrawable = new UdfpsFpDrawable(context);
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        mFingerprintView = findViewById(R.id.udfps_fpm_other_fp_view);
-        mFingerprintView.setImageDrawable(mFingerprintDrawable);
-    }
-
-    @Override
-    UdfpsDrawable getDrawable() {
-        return mFingerprintDrawable;
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherView.kt
new file mode 100644
index 0000000..4d6da8f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherView.kt
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.biometrics
+
+import android.content.Context
+import android.util.AttributeSet
+import android.widget.ImageView
+import com.android.systemui.R
+
+/**
+ * View corresponding with udfps_fpm_other_view.xml
+ */
+class UdfpsFpmOtherView(
+    context: Context,
+    attrs: AttributeSet?
+) : UdfpsAnimationView(context, attrs) {
+
+    private val fingerprintDrawable: UdfpsFpDrawable = UdfpsFpDrawable(context)
+    private lateinit var fingerprintView: ImageView
+
+    override fun onFinishInflate() {
+        fingerprintView = findViewById(R.id.udfps_fpm_other_fp_view)!!
+        fingerprintView.setImageDrawable(fingerprintDrawable)
+    }
+
+    override fun getDrawable(): UdfpsDrawable = fingerprintDrawable
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherViewController.java
deleted file mode 100644
index 97dca0f..0000000
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherViewController.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.biometrics;
-
-import android.annotation.NonNull;
-
-import com.android.systemui.dump.DumpManager;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.phone.SystemUIDialogManager;
-import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
-
-/**
- * Class that coordinates non-HBM animations for non keyguard, enrollment or biometric prompt
- * states.
- *
- * Currently only shows the fp drawable.
- */
-class UdfpsFpmOtherViewController extends UdfpsAnimationViewController<UdfpsFpmOtherView> {
-    protected UdfpsFpmOtherViewController(
-            @NonNull UdfpsFpmOtherView view,
-            @NonNull StatusBarStateController statusBarStateController,
-            @NonNull PanelExpansionStateManager panelExpansionStateManager,
-            @NonNull SystemUIDialogManager systemUIDialogManager,
-            @NonNull DumpManager dumpManager) {
-        super(view, statusBarStateController, panelExpansionStateManager, systemUIDialogManager,
-                dumpManager);
-    }
-
-    @Override
-    @NonNull String getTag() {
-        return "UdfpsFpmOtherViewController";
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherViewController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherViewController.kt
new file mode 100644
index 0000000..98205cf
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherViewController.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.systemui.biometrics
+
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.statusbar.phone.SystemUIDialogManager
+import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager
+
+/**
+ * Class that coordinates non-HBM animations for non keyguard, enrollment or biometric prompt
+ * states.
+ *
+ * Currently only shows the fp drawable.
+ */
+class UdfpsFpmOtherViewController(
+    view: UdfpsFpmOtherView,
+    statusBarStateController: StatusBarStateController,
+    panelExpansionStateManager: PanelExpansionStateManager,
+    systemUIDialogManager: SystemUIDialogManager,
+    dumpManager: DumpManager
+) : UdfpsAnimationViewController<UdfpsFpmOtherView>(
+    view,
+    statusBarStateController,
+    panelExpansionStateManager,
+    systemUIDialogManager,
+    dumpManager
+) {
+    override val tag = "UdfpsFpmOtherViewController"
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
index 3e8a568..d90a746 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
@@ -102,7 +102,7 @@
     }
 
     @Override
-    @NonNull String getTag() {
+    @NonNull protected String getTag() {
         return "UdfpsKeyguardViewController";
     }
 
@@ -115,21 +115,21 @@
     @Override
     protected void onViewAttached() {
         super.onViewAttached();
-        final float dozeAmount = mStatusBarStateController.getDozeAmount();
+        final float dozeAmount = getStatusBarStateController().getDozeAmount();
         mLastDozeAmount = dozeAmount;
         mStateListener.onDozeAmountChanged(dozeAmount, dozeAmount);
-        mStatusBarStateController.addCallback(mStateListener);
+        getStatusBarStateController().addCallback(mStateListener);
 
         mUdfpsRequested = false;
 
         mLaunchTransitionFadingAway = mKeyguardStateController.isLaunchTransitionFadingAway();
         mKeyguardStateController.addCallback(mKeyguardStateControllerCallback);
-        mStatusBarState = mStatusBarStateController.getState();
+        mStatusBarState = getStatusBarStateController().getState();
         mQsExpanded = mKeyguardViewManager.isQsExpanded();
         mInputBouncerHiddenAmount = KeyguardBouncer.EXPANSION_HIDDEN;
         mIsBouncerVisible = mKeyguardViewManager.bouncerIsOrWillBeShowing();
         mConfigurationController.addCallback(mConfigurationListener);
-        mPanelExpansionStateManager.addExpansionListener(mPanelExpansionListener);
+        getPanelExpansionStateManager().addExpansionListener(mPanelExpansionListener);
         updateAlpha();
         updatePauseAuth();
 
@@ -144,11 +144,11 @@
         mFaceDetectRunning = false;
 
         mKeyguardStateController.removeCallback(mKeyguardStateControllerCallback);
-        mStatusBarStateController.removeCallback(mStateListener);
+        getStatusBarStateController().removeCallback(mStateListener);
         mKeyguardViewManager.removeAlternateAuthInterceptor(mAlternateAuthInterceptor);
         mKeyguardUpdateMonitor.requestFaceAuthOnOccludingApp(false);
         mConfigurationController.removeCallback(mConfigurationListener);
-        mPanelExpansionStateManager.removeExpansionListener(mPanelExpansionListener);
+        getPanelExpansionStateManager().removeExpansionListener(mPanelExpansionListener);
         if (mLockScreenShadeTransitionController.getUdfpsKeyguardViewController() == this) {
             mLockScreenShadeTransitionController.setUdfpsKeyguardViewController(null);
         }
@@ -214,13 +214,13 @@
             return false;
         }
 
-        if (mUdfpsRequested && !mNotificationShadeVisible
+        if (mUdfpsRequested && !getNotificationShadeVisible()
                 && (!mIsBouncerVisible
                 || mInputBouncerHiddenAmount != KeyguardBouncer.EXPANSION_VISIBLE)) {
             return false;
         }
 
-        if (mDialogManager.shouldHideAffordance()) {
+        if (getDialogManager().shouldHideAffordance()) {
             return true;
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java
deleted file mode 100644
index 30e5aed..0000000
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java
+++ /dev/null
@@ -1,274 +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.biometrics;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.PointF;
-import android.graphics.RectF;
-import android.hardware.biometrics.SensorLocationInternal;
-import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
-import android.os.Build;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.text.TextUtils;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.MotionEvent;
-import android.view.Surface;
-import android.view.View;
-import android.widget.FrameLayout;
-
-import com.android.systemui.R;
-import com.android.systemui.biometrics.UdfpsHbmTypes.HbmType;
-import com.android.systemui.doze.DozeReceiver;
-
-/**
- * A view containing 1) A SurfaceView for HBM, and 2) A normal drawable view for all other
- * animations.
- */
-public class UdfpsView extends FrameLayout implements DozeReceiver, UdfpsIlluminator {
-    private static final String TAG = "UdfpsView";
-
-    private static final String SETTING_HBM_TYPE =
-            "com.android.systemui.biometrics.UdfpsSurfaceView.hbmType";
-    private static final @HbmType int DEFAULT_HBM_TYPE = UdfpsHbmTypes.LOCAL_HBM;
-
-    private static final int DEBUG_TEXT_SIZE_PX = 32;
-
-    @NonNull private final RectF mSensorRect;
-    @NonNull private final Paint mDebugTextPaint;
-    private final float mSensorTouchAreaCoefficient;
-    private final int mOnIlluminatedDelayMs;
-    private final @HbmType int mHbmType;
-
-    // Only used for UdfpsHbmTypes.GLOBAL_HBM.
-    @Nullable private UdfpsSurfaceView mGhbmView;
-    // Can be different for enrollment, BiometricPrompt, Keyguard, etc.
-    @Nullable private UdfpsAnimationViewController mAnimationViewController;
-    // Used to obtain the sensor location.
-    @NonNull private FingerprintSensorPropertiesInternal mSensorProps;
-    @Nullable private UdfpsHbmProvider mHbmProvider;
-    @Nullable private String mDebugMessage;
-    private boolean mIlluminationRequested;
-
-    public UdfpsView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-
-        TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.UdfpsView, 0,
-                0);
-        try {
-            if (!a.hasValue(R.styleable.UdfpsView_sensorTouchAreaCoefficient)) {
-                throw new IllegalArgumentException(
-                        "UdfpsView must contain sensorTouchAreaCoefficient");
-            }
-            mSensorTouchAreaCoefficient = a.getFloat(
-                    R.styleable.UdfpsView_sensorTouchAreaCoefficient, 0f);
-        } finally {
-            a.recycle();
-        }
-
-        mSensorRect = new RectF();
-
-        mDebugTextPaint = new Paint();
-        mDebugTextPaint.setAntiAlias(true);
-        mDebugTextPaint.setColor(Color.BLUE);
-        mDebugTextPaint.setTextSize(DEBUG_TEXT_SIZE_PX);
-
-        mOnIlluminatedDelayMs = mContext.getResources().getInteger(
-                com.android.internal.R.integer.config_udfps_illumination_transition_ms);
-
-        if (Build.IS_ENG || Build.IS_USERDEBUG) {
-            mHbmType = Settings.Secure.getIntForUser(mContext.getContentResolver(),
-                    SETTING_HBM_TYPE, DEFAULT_HBM_TYPE, UserHandle.USER_CURRENT);
-        } else {
-            mHbmType = DEFAULT_HBM_TYPE;
-        }
-    }
-
-    // Don't propagate any touch events to the child views.
-    @Override
-    public boolean onInterceptTouchEvent(MotionEvent ev) {
-        return mAnimationViewController == null
-                || !mAnimationViewController.shouldPauseAuth();
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        if (mHbmType == UdfpsHbmTypes.GLOBAL_HBM) {
-            mGhbmView = findViewById(R.id.hbm_view);
-        }
-    }
-
-    void setSensorProperties(@NonNull FingerprintSensorPropertiesInternal properties) {
-        mSensorProps = properties;
-    }
-
-    @Override
-    public void setHbmProvider(@Nullable UdfpsHbmProvider hbmProvider) {
-        mHbmProvider = hbmProvider;
-    }
-
-    @Override
-    public void dozeTimeTick() {
-        if (mAnimationViewController != null) {
-            mAnimationViewController.dozeTimeTick();
-        }
-    }
-
-    @Override
-    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        super.onLayout(changed, left, top, right, bottom);
-        int paddingX = mAnimationViewController == null ? 0
-                : mAnimationViewController.getPaddingX();
-        int paddingY = mAnimationViewController == null ? 0
-                : mAnimationViewController.getPaddingY();
-        final SensorLocationInternal location = mSensorProps.getLocation();
-        mSensorRect.set(
-                paddingX,
-                paddingY,
-                2 * location.sensorRadius + paddingX,
-                2 * location.sensorRadius + paddingY);
-
-        if (mAnimationViewController != null) {
-            mAnimationViewController.onSensorRectUpdated(new RectF(mSensorRect));
-        }
-    }
-
-    void onTouchOutsideView() {
-        if (mAnimationViewController != null) {
-            mAnimationViewController.onTouchOutsideView();
-        }
-    }
-
-    void setAnimationViewController(
-            @Nullable UdfpsAnimationViewController animationViewController) {
-        mAnimationViewController = animationViewController;
-    }
-
-    @Nullable UdfpsAnimationViewController getAnimationViewController() {
-        return mAnimationViewController;
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        Log.v(TAG, "onAttachedToWindow");
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        Log.v(TAG, "onDetachedFromWindow");
-    }
-
-    @Override
-    protected void onDraw(Canvas canvas) {
-        super.onDraw(canvas);
-        if (!mIlluminationRequested) {
-            if (!TextUtils.isEmpty(mDebugMessage)) {
-                canvas.drawText(mDebugMessage, 0, 160, mDebugTextPaint);
-            }
-        }
-    }
-
-    void setDebugMessage(String message) {
-        mDebugMessage = message;
-        postInvalidate();
-    }
-
-    boolean isWithinSensorArea(float x, float y) {
-        // The X and Y coordinates of the sensor's center.
-        final PointF translation = mAnimationViewController == null
-                ? new PointF(0, 0)
-                : mAnimationViewController.getTouchTranslation();
-        final float cx = mSensorRect.centerX() + translation.x;
-        final float cy = mSensorRect.centerY() + translation.y;
-        // Radii along the X and Y axes.
-        final float rx = (mSensorRect.right - mSensorRect.left) / 2.0f;
-        final float ry = (mSensorRect.bottom - mSensorRect.top) / 2.0f;
-
-        return x > (cx - rx * mSensorTouchAreaCoefficient)
-                && x < (cx + rx * mSensorTouchAreaCoefficient)
-                && y > (cy - ry * mSensorTouchAreaCoefficient)
-                && y < (cy + ry * mSensorTouchAreaCoefficient)
-                && !mAnimationViewController.shouldPauseAuth();
-    }
-
-    boolean isIlluminationRequested() {
-        return mIlluminationRequested;
-    }
-
-    /**
-     * @param onIlluminatedRunnable Runs when the first illumination frame reaches the panel.
-     */
-    @Override
-    public void startIllumination(@Nullable Runnable onIlluminatedRunnable) {
-        mIlluminationRequested = true;
-        if (mAnimationViewController != null) {
-            mAnimationViewController.onIlluminationStarting();
-        }
-
-        if (mGhbmView != null) {
-            mGhbmView.setGhbmIlluminationListener(this::doIlluminate);
-            mGhbmView.setVisibility(View.VISIBLE);
-            mGhbmView.startGhbmIllumination(onIlluminatedRunnable);
-        } else {
-            doIlluminate(null /* surface */, onIlluminatedRunnable);
-        }
-    }
-
-    private void doIlluminate(@Nullable Surface surface, @Nullable Runnable onIlluminatedRunnable) {
-        if (mGhbmView != null && surface == null) {
-            Log.e(TAG, "doIlluminate | surface must be non-null for GHBM");
-        }
-        if (mHbmProvider != null) {
-            mHbmProvider.enableHbm(mHbmType, surface, () -> {
-                if (mGhbmView != null) {
-                    mGhbmView.drawIlluminationDot(mSensorRect);
-                }
-                if (onIlluminatedRunnable != null) {
-                    // No framework API can reliably tell when a frame reaches the panel. A timeout
-                    // is the safest solution.
-                    postDelayed(onIlluminatedRunnable, mOnIlluminatedDelayMs);
-                } else {
-                    Log.w(TAG, "doIlluminate | onIlluminatedRunnable is null");
-                }
-            });
-        }
-    }
-
-    @Override
-    public void stopIllumination() {
-        mIlluminationRequested = false;
-        if (mAnimationViewController != null) {
-            mAnimationViewController.onIlluminationStopped();
-        }
-        if (mGhbmView != null) {
-            mGhbmView.setGhbmIlluminationListener(null);
-            mGhbmView.setVisibility(View.INVISIBLE);
-        }
-        if (mHbmProvider != null) {
-            mHbmProvider.disableHbm(null /* onHbmDisabled */);
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.kt
new file mode 100644
index 0000000..9fbc458
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.kt
@@ -0,0 +1,220 @@
+/*
+ * 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.biometrics
+
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.Paint
+import android.graphics.PointF
+import android.graphics.RectF
+import android.hardware.fingerprint.FingerprintSensorPropertiesInternal
+import android.os.Build
+import android.os.UserHandle
+import android.provider.Settings
+import android.util.AttributeSet
+import android.util.Log
+import android.view.MotionEvent
+import android.view.Surface
+import android.widget.FrameLayout
+import com.android.systemui.R
+import com.android.systemui.doze.DozeReceiver
+import com.android.systemui.biometrics.UdfpsHbmTypes.HbmType
+
+private const val TAG = "UdfpsView"
+private const val SETTING_HBM_TYPE = "com.android.systemui.biometrics.UdfpsSurfaceView.hbmType"
+@HbmType
+private const val DEFAULT_HBM_TYPE = UdfpsHbmTypes.LOCAL_HBM
+
+/**
+ * A view containing 1) A SurfaceView for HBM, and 2) A normal drawable view for all other
+ * animations.
+ */
+class UdfpsView(
+    context: Context,
+    attrs: AttributeSet?
+) : FrameLayout(context, attrs), DozeReceiver, UdfpsIlluminator {
+
+    private val sensorRect = RectF()
+    private var hbmProvider: UdfpsHbmProvider? = null
+    private val debugTextPaint = Paint().apply {
+        isAntiAlias = true
+        color = Color.BLUE
+        textSize = 32f
+    }
+
+    private val sensorTouchAreaCoefficient: Float =
+        context.theme.obtainStyledAttributes(attrs, R.styleable.UdfpsView, 0, 0).use { a ->
+            require(a.hasValue(R.styleable.UdfpsView_sensorTouchAreaCoefficient)) {
+                "UdfpsView must contain sensorTouchAreaCoefficient"
+            }
+            a.getFloat(R.styleable.UdfpsView_sensorTouchAreaCoefficient, 0f)
+        }
+
+    private val onIlluminatedDelayMs = context.resources.getInteger(
+        com.android.internal.R.integer.config_udfps_illumination_transition_ms
+    ).toLong()
+
+    @HbmType
+    private val hbmType = if (Build.IS_ENG || Build.IS_USERDEBUG) {
+        Settings.Secure.getIntForUser(
+            context.contentResolver,
+            SETTING_HBM_TYPE,
+            DEFAULT_HBM_TYPE,
+            UserHandle.USER_CURRENT
+        )
+    } else {
+        DEFAULT_HBM_TYPE
+    }
+
+    // Only used for UdfpsHbmTypes.GLOBAL_HBM.
+    private var ghbmView: UdfpsSurfaceView? = null
+
+    /** View controller (can be different for enrollment, BiometricPrompt, Keyguard, etc.). */
+    var animationViewController: UdfpsAnimationViewController<*>? = null
+
+    /** Properties used to obtain the sensor location. */
+    var sensorProperties: FingerprintSensorPropertiesInternal? = null
+
+    /** Debug message. */
+    var debugMessage: String? = null
+        set(value) {
+            field = value
+            postInvalidate()
+        }
+
+    /** When [startIllumination] has been called but not stopped via [stopIllumination]. */
+    var isIlluminationRequested: Boolean = false
+        private set
+
+    override fun setHbmProvider(provider: UdfpsHbmProvider?) {
+        hbmProvider = provider
+    }
+
+    // Don't propagate any touch events to the child views.
+    override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
+        return (animationViewController == null || !animationViewController!!.shouldPauseAuth())
+    }
+
+    override fun onFinishInflate() {
+        if (hbmType == UdfpsHbmTypes.GLOBAL_HBM) {
+            ghbmView = findViewById(R.id.hbm_view)
+        }
+    }
+
+    override fun dozeTimeTick() {
+        animationViewController?.dozeTimeTick()
+    }
+
+    override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
+        super.onLayout(changed, left, top, right, bottom)
+
+        val paddingX = animationViewController?.paddingX ?: 0
+        val paddingY = animationViewController?.paddingY ?: 0
+        val sensorRadius = sensorProperties?.location?.sensorRadius ?: 0
+
+        sensorRect.set(
+            paddingX.toFloat(),
+            paddingY.toFloat(),
+            (2 * sensorRadius + paddingX).toFloat(),
+            (2 * sensorRadius + paddingY).toFloat()
+        )
+        animationViewController?.onSensorRectUpdated(RectF(sensorRect))
+    }
+
+    fun onTouchOutsideView() {
+        animationViewController?.onTouchOutsideView()
+    }
+
+    override fun onAttachedToWindow() {
+        super.onAttachedToWindow()
+        Log.v(TAG, "onAttachedToWindow")
+    }
+
+    override fun onDetachedFromWindow() {
+        super.onDetachedFromWindow()
+        Log.v(TAG, "onDetachedFromWindow")
+    }
+
+    override fun onDraw(canvas: Canvas) {
+        super.onDraw(canvas)
+        if (!isIlluminationRequested) {
+            if (!debugMessage.isNullOrEmpty()) {
+                canvas.drawText(debugMessage!!, 0f, 160f, debugTextPaint)
+            }
+        }
+    }
+
+    fun isWithinSensorArea(x: Float, y: Float): Boolean {
+        // The X and Y coordinates of the sensor's center.
+        val translation = animationViewController?.touchTranslation ?: PointF(0f, 0f)
+        val cx = sensorRect.centerX() + translation.x
+        val cy = sensorRect.centerY() + translation.y
+        // Radii along the X and Y axes.
+        val rx = (sensorRect.right - sensorRect.left) / 2.0f
+        val ry = (sensorRect.bottom - sensorRect.top) / 2.0f
+
+        return x > cx - rx * sensorTouchAreaCoefficient &&
+            x < cx + rx * sensorTouchAreaCoefficient &&
+            y > cy - ry * sensorTouchAreaCoefficient &&
+            y < cy + ry * sensorTouchAreaCoefficient &&
+            !(animationViewController?.shouldPauseAuth() ?: false)
+    }
+
+    /**
+     * Start and run [onIlluminatedRunnable] when the first illumination frame reaches the panel.
+     */
+    override fun startIllumination(onIlluminatedRunnable: Runnable?) {
+        isIlluminationRequested = true
+        animationViewController?.onIlluminationStarting()
+
+        val gView = ghbmView
+        if (gView != null) {
+            gView.setGhbmIlluminationListener(this::doIlluminate)
+            gView.visibility = VISIBLE
+            gView.startGhbmIllumination(onIlluminatedRunnable)
+        } else {
+            doIlluminate(null /* surface */, onIlluminatedRunnable)
+        }
+    }
+
+    private fun doIlluminate(surface: Surface?, onIlluminatedRunnable: Runnable?) {
+        if (ghbmView != null && surface == null) {
+            Log.e(TAG, "doIlluminate | surface must be non-null for GHBM")
+        }
+
+        hbmProvider?.enableHbm(hbmType, surface) {
+            ghbmView?.drawIlluminationDot(sensorRect)
+            if (onIlluminatedRunnable != null) {
+                // No framework API can reliably tell when a frame reaches the panel. A timeout
+                // is the safest solution.
+                postDelayed(onIlluminatedRunnable, onIlluminatedDelayMs)
+            } else {
+                Log.w(TAG, "doIlluminate | onIlluminatedRunnable is null")
+            }
+        }
+    }
+
+    override fun stopIllumination() {
+        isIlluminationRequested = false
+        animationViewController?.onIlluminationStopped()
+        ghbmView?.let { view ->
+            view.setGhbmIlluminationListener(null)
+            view.visibility = INVISIBLE
+        }
+        hbmProvider?.disableHbm(null /* onHbmDisabled */)
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
index af06979..cffb2f7 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
@@ -23,8 +23,9 @@
 import com.android.systemui.SystemUIAppComponentFactory;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.keyguard.KeyguardSliceProvider;
-import com.android.systemui.media.taptotransfer.MediaTttChipController;
 import com.android.systemui.media.taptotransfer.MediaTttCommandLineHelper;
+import com.android.systemui.media.taptotransfer.receiver.MediaTttChipControllerReceiver;
+import com.android.systemui.media.taptotransfer.sender.MediaTttChipControllerSender;
 import com.android.systemui.people.PeopleProvider;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.unfold.SysUIUnfoldComponent;
@@ -134,7 +135,8 @@
         });
         getNaturalRotationUnfoldProgressProvider().ifPresent(o -> o.init());
         // No init method needed, just needs to be gotten so that it's created.
-        getMediaTttChipController();
+        getMediaTttChipControllerSender();
+        getMediaTttChipControllerReceiver();
         getMediaTttCommandLineHelper();
         getUnfoldLatencyTracker().init();
     }
@@ -190,7 +192,10 @@
     Optional<NaturalRotationUnfoldProgressProvider> getNaturalRotationUnfoldProgressProvider();
 
     /** */
-    Optional<MediaTttChipController> getMediaTttChipController();
+    Optional<MediaTttChipControllerSender> getMediaTttChipControllerSender();
+
+    /** */
+    Optional<MediaTttChipControllerReceiver> getMediaTttChipControllerReceiver();
 
     /** */
     Optional<MediaTttCommandLineHelper> getMediaTttCommandLineHelper();
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
index 3426148..9dddbb1 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
@@ -25,7 +25,7 @@
 import com.android.systemui.biometrics.AuthController;
 import com.android.systemui.communal.CommunalManagerUpdater;
 import com.android.systemui.dreams.DreamOverlayRegistrant;
-import com.android.systemui.dreams.appwidgets.AppWidgetOverlayPrimer;
+import com.android.systemui.dreams.appwidgets.ComplicationPrimer;
 import com.android.systemui.globalactions.GlobalActionsComponent;
 import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.keyguard.dagger.KeyguardModule;
@@ -202,9 +202,9 @@
     /** Inject into AppWidgetOverlayPrimer. */
     @Binds
     @IntoMap
-    @ClassKey(AppWidgetOverlayPrimer.class)
+    @ClassKey(ComplicationPrimer.class)
     public abstract CoreStartable bindAppWidgetOverlayPrimer(
-            AppWidgetOverlayPrimer appWidgetOverlayPrimer);
+            ComplicationPrimer complicationPrimer);
 
     /** Inject into CommunalManagerUpdater. */
     @Binds
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
index 9c25b35..2beed4c 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
@@ -40,7 +40,6 @@
     void extendPulse(int reason);
 
     void setAnimateWakeup(boolean animateWakeup);
-    void setAnimateScreenOff(boolean animateScreenOff);
 
     /**
      * Reports that a tap event happend on the Sensors Low Power Island.
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
index b2fe3bb..e568b82 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
@@ -21,30 +21,21 @@
 
 import android.app.AlarmManager;
 import android.content.Context;
-import android.content.res.Configuration;
 import android.os.Handler;
 import android.os.SystemClock;
-import android.provider.Settings;
 import android.text.format.Formatter;
 import android.util.Log;
 
-import com.android.internal.annotations.VisibleForTesting;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.doze.dagger.DozeScope;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.phone.DozeParameters;
-import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.tuner.TunerService;
-import com.android.systemui.unfold.FoldAodAnimationController;
-import com.android.systemui.unfold.FoldAodAnimationController.FoldAodAnimationStatus;
-import com.android.systemui.unfold.SysUIUnfoldComponent;
 import com.android.systemui.util.AlarmTimeout;
 import com.android.systemui.util.wakelock.WakeLock;
 
 import java.util.Calendar;
-import java.util.Optional;
 
 import javax.inject.Inject;
 
@@ -52,9 +43,7 @@
  * The policy controlling doze.
  */
 @DozeScope
-public class DozeUi implements DozeMachine.Part, TunerService.Tunable,
-        ConfigurationController.ConfigurationListener, FoldAodAnimationStatus,
-        StatusBarStateController.StateListener {
+public class DozeUi implements DozeMachine.Part {
     // if enabled, calls dozeTimeTick() whenever the time changes:
     private static final boolean BURN_IN_TESTING_ENABLED = false;
     private static final long TIME_TICK_DEADLINE_MILLIS = 90 * 1000; // 1.5min
@@ -62,26 +51,15 @@
     private final DozeHost mHost;
     private final Handler mHandler;
     private final WakeLock mWakeLock;
-    private final FoldAodAnimationController mFoldAodAnimationController;
     private DozeMachine mMachine;
     private final AlarmTimeout mTimeTicker;
     private final boolean mCanAnimateTransition;
     private final DozeParameters mDozeParameters;
     private final DozeLog mDozeLog;
     private final StatusBarStateController mStatusBarStateController;
-    private final TunerService mTunerService;
-    private final ConfigurationController mConfigurationController;
-
-    private boolean mKeyguardShowing;
     private final KeyguardUpdateMonitorCallback mKeyguardVisibilityCallback =
             new KeyguardUpdateMonitorCallback() {
                 @Override
-                public void onKeyguardVisibilityChanged(boolean showing) {
-                    mKeyguardShowing = showing;
-                    updateAnimateScreenOff();
-                }
-
-                @Override
                 public void onTimeChanged() {
                     if (BURN_IN_TESTING_ENABLED && mStatusBarStateController.isDozing()) {
                         // update whenever the time changes for manual burn in testing
@@ -91,11 +69,6 @@
                         mHandler.post(mWakeLock.wrap(() -> {}));
                     }
                 }
-
-                @Override
-                public void onShadeExpandedChanged(boolean expanded) {
-                    updateAnimateScreenOff();
-                }
             };
 
     private long mLastTimeTickElapsed = 0;
@@ -104,10 +77,8 @@
     public DozeUi(Context context, AlarmManager alarmManager,
             WakeLock wakeLock, DozeHost host, @Main Handler handler,
             DozeParameters params, KeyguardUpdateMonitor keyguardUpdateMonitor,
-            DozeLog dozeLog, TunerService tunerService,
             StatusBarStateController statusBarStateController,
-            Optional<SysUIUnfoldComponent> sysUiUnfoldComponent,
-            ConfigurationController configurationController) {
+            DozeLog dozeLog) {
         mContext = context;
         mWakeLock = wakeLock;
         mHost = host;
@@ -117,31 +88,7 @@
         mTimeTicker = new AlarmTimeout(alarmManager, this::onTimeTick, "doze_time_tick", handler);
         keyguardUpdateMonitor.registerCallback(mKeyguardVisibilityCallback);
         mDozeLog = dozeLog;
-        mTunerService = tunerService;
         mStatusBarStateController = statusBarStateController;
-        mStatusBarStateController.addCallback(this);
-
-        mTunerService.addTunable(this, Settings.Secure.DOZE_ALWAYS_ON);
-
-        mConfigurationController = configurationController;
-        mConfigurationController.addCallback(this);
-
-        mFoldAodAnimationController = sysUiUnfoldComponent
-                .map(SysUIUnfoldComponent::getFoldAodAnimationController).orElse(null);
-
-        if (mFoldAodAnimationController != null) {
-            mFoldAodAnimationController.addCallback(this);
-        }
-    }
-
-    @Override
-    public void destroy() {
-        mTunerService.removeTunable(this);
-        mConfigurationController.removeCallback(this);
-
-        if (mFoldAodAnimationController != null) {
-            mFoldAodAnimationController.removeCallback(this);
-        }
     }
 
     @Override
@@ -149,22 +96,6 @@
         mMachine = dozeMachine;
     }
 
-    /**
-     * Decide if we're taking over the screen-off animation
-     * when the device was configured to skip doze after screen off.
-     */
-    private void updateAnimateScreenOff() {
-        if (mCanAnimateTransition) {
-            final boolean controlScreenOff =
-                    mDozeParameters.getAlwaysOn()
-                    && (mKeyguardShowing || mDozeParameters.shouldControlUnlockedScreenOff())
-                    && !mHost.isPowerSaveActive();
-            mDozeParameters.setControlScreenOffAnimation(controlScreenOff);
-            mHost.setAnimateScreenOff(controlScreenOff
-                    && mDozeParameters.shouldAnimateDozingChange());
-        }
-    }
-
     private void pulseWhileDozing(int reason) {
         mHost.pulseWhileDozing(
                 new DozeHost.PulseCallback() {
@@ -293,34 +224,4 @@
 
         scheduleTimeTick();
     }
-
-    @VisibleForTesting
-    KeyguardUpdateMonitorCallback getKeyguardCallback() {
-        return mKeyguardVisibilityCallback;
-    }
-
-    @Override
-    public void onTuningChanged(String key, String newValue) {
-        if (key.equals(Settings.Secure.DOZE_ALWAYS_ON)) {
-            updateAnimateScreenOff();
-        }
-    }
-
-    @Override
-    public void onConfigChanged(Configuration newConfig) {
-        updateAnimateScreenOff();
-    }
-
-    /**
-     * Called when StatusBar state changed, could affect unlocked screen off animation state
-     */
-    @Override
-    public void onStatePostChange() {
-        updateAnimateScreenOff();
-    }
-
-    @Override
-    public void onFoldToAodAnimationChanged() {
-        updateAnimateScreenOff();
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/ComplicationHost.java b/packages/SystemUI/src/com/android/systemui/dreams/ComplicationHost.java
new file mode 100644
index 0000000..7c3152f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dreams/ComplicationHost.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 com.android.systemui.dreams;
+
+import android.view.View;
+
+/**
+ * A collection of interfaces related to hosting a complication.
+ */
+public abstract class ComplicationHost {
+    /**
+     * An interface for the callback from the complication provider to indicate when the
+     * complication is ready.
+     */
+    public interface CreationCallback {
+        /**
+         * Called to inform the complication view is ready to be placed within the visual space.
+         * @param view The view representing the complication.
+         * @param layoutParams The parameters to create the view with.
+         */
+        void onCreated(View view, ComplicationHostView.LayoutParams layoutParams);
+    }
+
+    /**
+     * An interface for the callback from the complication provider to signal interactions in the
+     * complication.
+     */
+    public interface InteractionCallback {
+        /**
+         * Called to signal the calling complication would like to exit the dream.
+         */
+        void onExit();
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/OverlayHostView.java b/packages/SystemUI/src/com/android/systemui/dreams/ComplicationHostView.java
similarity index 67%
rename from packages/SystemUI/src/com/android/systemui/dreams/OverlayHostView.java
rename to packages/SystemUI/src/com/android/systemui/dreams/ComplicationHostView.java
index 7870426..a67dd5c 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/OverlayHostView.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/ComplicationHostView.java
@@ -22,22 +22,23 @@
 import androidx.constraintlayout.widget.ConstraintLayout;
 
 /**
- * {@link OverlayHostView} is the container view for housing overlays ontop of a dream.
+ * {@link ComplicationHostView} is the container view for housing complications above of a dream.
  */
-public class OverlayHostView extends ConstraintLayout {
-    public OverlayHostView(Context context) {
+public class ComplicationHostView extends ConstraintLayout {
+    public ComplicationHostView(Context context) {
         super(context, null);
     }
 
-    public OverlayHostView(Context context, AttributeSet attrs) {
+    public ComplicationHostView(Context context, AttributeSet attrs) {
         super(context, attrs, 0);
     }
 
-    public OverlayHostView(Context context, AttributeSet attrs, int defStyleAttr) {
+    public ComplicationHostView(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr, 0);
     }
 
-    public OverlayHostView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+    public ComplicationHostView(Context context, AttributeSet attrs, int defStyleAttr,
+            int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/ComplicationProvider.java b/packages/SystemUI/src/com/android/systemui/dreams/ComplicationProvider.java
new file mode 100644
index 0000000..099e379
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dreams/ComplicationProvider.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.dreams;
+
+import android.content.Context;
+
+/**
+ * {@link ComplicationProvider} is an interface for defining entities that can supply complications
+ * to show over a dream. Presentation components such as the {@link DreamOverlayService} supply
+ * implementations with the necessary context for constructing such overlays.
+ */
+public interface ComplicationProvider {
+    /**
+     * Called when the {@link ComplicationHost} requests the associated complication be produced.
+     *
+     * @param context The {@link Context} used to construct the view.
+     * @param creationCallback The callback to inform the complication has been created.
+     * @param interactionCallback The callback to inform the complication has been interacted with.
+     */
+    void onCreateComplication(Context context, ComplicationHost.CreationCallback creationCallback,
+            ComplicationHost.InteractionCallback interactionCallback);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
new file mode 100644
index 0000000..572bb44
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.dreams;
+
+import android.graphics.Rect;
+import android.graphics.Region;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+
+import androidx.constraintlayout.widget.ConstraintLayout;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.R;
+import com.android.systemui.dreams.dagger.DreamOverlayComponent;
+import com.android.systemui.dreams.dagger.DreamOverlayModule;
+import com.android.systemui.util.ViewController;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+/**
+ * View controller for {@link DreamOverlayContainerView}.
+ */
+@DreamOverlayComponent.DreamOverlayScope
+public class DreamOverlayContainerViewController extends ViewController<DreamOverlayContainerView> {
+    // The height of the area at the top of the dream overlay to allow dragging down the
+    // notifications shade.
+    private final int mDreamOverlayNotificationsDragAreaHeight;
+    private final DreamOverlayStatusBarViewController mStatusBarViewController;
+
+    // The dream overlay's content view, which is located below the status bar (in z-order) and is
+    // the space into which widgets are placed.
+    private final ViewGroup mDreamOverlayContentView;
+
+    // A hook into the internal inset calculation where we declare the overlays as the only
+    // touchable regions.
+    private final ViewTreeObserver.OnComputeInternalInsetsListener
+            mOnComputeInternalInsetsListener =
+            new ViewTreeObserver.OnComputeInternalInsetsListener() {
+                @Override
+                public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo inoutInfo) {
+                    inoutInfo.setTouchableInsets(
+                            ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
+                    final Region region = new Region();
+                    final Rect rect = new Rect();
+                    final int childCount = mDreamOverlayContentView.getChildCount();
+                    for (int i = 0; i < childCount; i++) {
+                        View child = mDreamOverlayContentView.getChildAt(i);
+                        if (child.getGlobalVisibleRect(rect)) {
+                            region.op(rect, Region.Op.UNION);
+                        }
+                    }
+
+                    // Add the notifications drag area to the tap region (otherwise the
+                    // notifications shade can't be dragged down).
+                    if (mDreamOverlayContentView.getGlobalVisibleRect(rect)) {
+                        rect.bottom = rect.top + mDreamOverlayNotificationsDragAreaHeight;
+                        region.op(rect, Region.Op.UNION);
+                    }
+
+                    inoutInfo.touchableRegion.set(region);
+                }
+            };
+
+    @Inject
+    public DreamOverlayContainerViewController(
+            DreamOverlayContainerView containerView,
+            @Named(DreamOverlayModule.DREAM_OVERLAY_CONTENT_VIEW) ViewGroup contentView,
+            DreamOverlayStatusBarViewController statusBarViewController) {
+        super(containerView);
+        mDreamOverlayContentView = contentView;
+        mStatusBarViewController = statusBarViewController;
+        mDreamOverlayNotificationsDragAreaHeight =
+                mView.getResources().getDimensionPixelSize(
+                        R.dimen.dream_overlay_notifications_drag_area_height);
+    }
+
+    @Override
+    protected void onInit() {
+        mStatusBarViewController.init();
+    }
+
+    @Override
+    protected void onViewAttached() {
+        mView.getViewTreeObserver()
+                .addOnComputeInternalInsetsListener(mOnComputeInternalInsetsListener);
+    }
+
+    @Override
+    protected void onViewDetached() {
+        mView.getViewTreeObserver()
+                .removeOnComputeInternalInsetsListener(mOnComputeInternalInsetsListener);
+    }
+
+    void addOverlay(View overlayView, ConstraintLayout.LayoutParams layoutParams) {
+        mDreamOverlayContentView.addView(overlayView, layoutParams);
+    }
+
+    View getContainerView() {
+        return mView;
+    }
+
+    void removeAllOverlays() {
+        mDreamOverlayContentView.removeAllViews();
+    }
+
+    @VisibleForTesting
+    int getDreamOverlayNotificationsDragAreaHeight() {
+        return mDreamOverlayNotificationsDragAreaHeight;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
index 393f039..a53120f 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
@@ -17,13 +17,8 @@
 package com.android.systemui.dreams;
 
 import android.content.Context;
-import android.graphics.Rect;
-import android.graphics.Region;
 import android.graphics.drawable.ColorDrawable;
 import android.util.Log;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewTreeObserver;
 import android.view.Window;
 import android.view.WindowInsets;
 import android.view.WindowManager;
@@ -40,7 +35,7 @@
 import javax.inject.Inject;
 
 /**
- * The {@link DreamOverlayService} is responsible for placing overlays on top of a dream. The
+ * The {@link DreamOverlayService} is responsible for placing an overlay on top of a dream. The
  * dream reaches directly out to the service with a Window reference (via LayoutParams), which the
  * service uses to insert its own child Window into the dream's parent Window.
  */
@@ -52,61 +47,20 @@
     private final Context mContext;
     // The Executor ensures actions and ui updates happen on the same thread.
     private final Executor mExecutor;
-    // The state controller informs the service of updates to the overlays present.
+    // The state controller informs the service of updates to the complications present.
     private final DreamOverlayStateController mStateController;
-    // The component used to resolve dream overlay dependencies.
-    private final DreamOverlayComponent mDreamOverlayComponent;
+    // A controller for the dream overlay container view (which contains both the status bar and the
+    // content area).
+    private final DreamOverlayContainerViewController mDreamOverlayContainerViewController;
 
-    // The dream overlay's content view, which is located below the status bar (in z-order) and is
-    // the space into which widgets are placed.
-    private ViewGroup mDreamOverlayContentView;
+    // A reference to the {@link Window} used to hold the dream overlay.
+    private Window mWindow;
 
     private final DreamOverlayStateController.Callback mOverlayStateCallback =
             new DreamOverlayStateController.Callback() {
                 @Override
-                public void onOverlayChanged() {
-                    mExecutor.execute(() -> reloadOverlaysLocked());
-                }
-            };
-
-    // The service listens to view changes in order to declare that input occurring in areas outside
-    // the overlay should be passed through to the dream underneath.
-    private final View.OnAttachStateChangeListener mRootViewAttachListener =
-            new View.OnAttachStateChangeListener() {
-                @Override
-                public void onViewAttachedToWindow(View v) {
-                    v.getViewTreeObserver()
-                            .addOnComputeInternalInsetsListener(mOnComputeInternalInsetsListener);
-                }
-
-                @Override
-                public void onViewDetachedFromWindow(View v) {
-                    v.getViewTreeObserver()
-                            .removeOnComputeInternalInsetsListener(
-                                    mOnComputeInternalInsetsListener);
-                }
-            };
-
-    // A hook into the internal inset calculation where we declare the overlays as the only
-    // touchable regions.
-    private final ViewTreeObserver.OnComputeInternalInsetsListener
-            mOnComputeInternalInsetsListener =
-            new ViewTreeObserver.OnComputeInternalInsetsListener() {
-                @Override
-                public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo inoutInfo) {
-                    if (mDreamOverlayContentView != null) {
-                        inoutInfo.setTouchableInsets(
-                                ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
-                        final Region region = new Region();
-                        for (int i = 0; i < mDreamOverlayContentView.getChildCount(); i++) {
-                            View child = mDreamOverlayContentView.getChildAt(i);
-                            final Rect rect = new Rect();
-                            child.getGlobalVisibleRect(rect);
-                            region.op(rect, Region.Op.UNION);
-                        }
-
-                        inoutInfo.touchableRegion.set(region);
-                    }
+                public void onComplicationsChanged() {
+                    mExecutor.execute(() -> reloadComplicationsLocked());
                 }
             };
 
@@ -119,87 +73,76 @@
         mContext = context;
         mExecutor = executor;
         mStateController = overlayStateController;
-        mDreamOverlayComponent = dreamOverlayComponentFactory.create();
+        mDreamOverlayContainerViewController =
+                dreamOverlayComponentFactory.create().getDreamOverlayContainerViewController();
 
         mStateController.addCallback(mOverlayStateCallback);
     }
 
     @Override
+    public void onDestroy() {
+        final WindowManager windowManager = mContext.getSystemService(WindowManager.class);
+        windowManager.removeView(mWindow.getDecorView());
+        mStateController.removeCallback(mOverlayStateCallback);
+        super.onDestroy();
+    }
+
+    @Override
     public void onStartDream(@NonNull WindowManager.LayoutParams layoutParams) {
         mExecutor.execute(() -> addOverlayWindowLocked(layoutParams));
     }
 
-    private void reloadOverlaysLocked() {
-        if (mDreamOverlayContentView == null) {
-            return;
-        }
-        mDreamOverlayContentView.removeAllViews();
-        for (OverlayProvider overlayProvider : mStateController.getOverlays()) {
-            addOverlay(overlayProvider);
+    private void reloadComplicationsLocked() {
+        mDreamOverlayContainerViewController.removeAllOverlays();
+        for (ComplicationProvider overlayProvider : mStateController.getComplications()) {
+            addComplication(overlayProvider);
         }
     }
 
     /**
-     * Inserts {@link Window} to host dream overlays into the dream's parent window. Must be called
-     * from the main executing thread. The window attributes closely mirror those that are set by
-     * the {@link android.service.dreams.DreamService} on the dream Window.
+     * Inserts {@link Window} to host the dream overlay into the dream's parent window. Must be
+     * called from the main executing thread. The window attributes closely mirror those that are
+     * set by the {@link android.service.dreams.DreamService} on the dream Window.
      * @param layoutParams The {@link android.view.WindowManager.LayoutParams} which allow inserting
      *                     into the dream window.
      */
     private void addOverlayWindowLocked(WindowManager.LayoutParams layoutParams) {
-        final PhoneWindow window = new PhoneWindow(mContext);
-        window.setAttributes(layoutParams);
-        window.setWindowManager(null, layoutParams.token, "DreamOverlay", true);
+        mWindow = new PhoneWindow(mContext);
+        mWindow.setAttributes(layoutParams);
+        mWindow.setWindowManager(null, layoutParams.token, "DreamOverlay", true);
 
-        window.setBackgroundDrawable(new ColorDrawable(0));
+        mWindow.setBackgroundDrawable(new ColorDrawable(0));
 
-        window.clearFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
-        window.addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
-        window.requestFeature(Window.FEATURE_NO_TITLE);
+        mWindow.clearFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
+        mWindow.addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
+        mWindow.requestFeature(Window.FEATURE_NO_TITLE);
         // Hide all insets when the dream is showing
-        window.getDecorView().getWindowInsetsController().hide(WindowInsets.Type.systemBars());
-        window.setDecorFitsSystemWindows(false);
+        mWindow.getDecorView().getWindowInsetsController().hide(WindowInsets.Type.systemBars());
+        mWindow.setDecorFitsSystemWindows(false);
 
         if (DEBUG) {
             Log.d(TAG, "adding overlay window to dream");
         }
 
-        window.setContentView(mDreamOverlayComponent.getDreamOverlayContainerView());
-
-        mDreamOverlayContentView = mDreamOverlayComponent.getDreamOverlayContentView();
-        mDreamOverlayContentView.addOnAttachStateChangeListener(mRootViewAttachListener);
-
-        mDreamOverlayComponent.getDreamOverlayStatusBarViewController().init();
+        mDreamOverlayContainerViewController.init();
+        mWindow.setContentView(mDreamOverlayContainerViewController.getContainerView());
 
         final WindowManager windowManager = mContext.getSystemService(WindowManager.class);
-        windowManager.addView(window.getDecorView(), window.getAttributes());
-        mExecutor.execute(this::reloadOverlaysLocked);
+        windowManager.addView(mWindow.getDecorView(), mWindow.getAttributes());
+        mExecutor.execute(this::reloadComplicationsLocked);
     }
 
     @VisibleForTesting
-    protected void addOverlay(OverlayProvider provider) {
-        provider.onCreateOverlay(mContext,
+    protected void addComplication(ComplicationProvider provider) {
+        provider.onCreateComplication(mContext,
                 (view, layoutParams) -> {
                     // Always move UI related work to the main thread.
-                    mExecutor.execute(() -> {
-                        if (mDreamOverlayContentView == null) {
-                            return;
-                        }
-
-                        mDreamOverlayContentView.addView(view, layoutParams);
-                    });
+                    mExecutor.execute(() -> mDreamOverlayContainerViewController
+                            .addOverlay(view, layoutParams));
                 },
                 () -> {
                     // The Callback is set on the main thread.
-                    mExecutor.execute(() -> {
-                        requestExit();
-                    });
+                    mExecutor.execute(this::requestExit);
                 });
     }
-
-    @Override
-    public void onDestroy() {
-        mStateController.removeCallback(mOverlayStateCallback);
-        super.onDestroy();
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java
index d248a9e..66679bb 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java
@@ -17,45 +17,51 @@
 package com.android.systemui.dreams;
 
 import androidx.annotation.NonNull;
+import androidx.concurrent.futures.CallbackToFutureAdapter;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.statusbar.policy.CallbackController;
 
+import com.google.common.util.concurrent.ListenableFuture;
+
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.Objects;
+import java.util.concurrent.Executor;
 
 import javax.inject.Inject;
 
 /**
- * {@link DreamOverlayStateController} is the source of truth for Dream overlay configurations.
- * Clients can register as listeners for changes to the overlay composition and can query for the
- * overlays on-demand.
+ * {@link DreamOverlayStateController} is the source of truth for Dream overlay configurations and
+ * state. Clients can register as listeners for changes to the overlay composition and can query for
+ * the complications on-demand.
  */
 @SysUISingleton
 public class DreamOverlayStateController implements
         CallbackController<DreamOverlayStateController.Callback> {
-    // A counter for guaranteeing unique overlay tokens within the scope of this state controller.
-    private int mNextOverlayTokenId = 0;
+    // A counter for guaranteeing unique complications tokens within the scope of this state
+    // controller.
+    private int mNextComplicationTokenId = 0;
 
     /**
-     * {@link OverlayToken} provides a unique key for identifying {@link OverlayProvider}
+     * {@link ComplicationToken} provides a unique key for identifying {@link ComplicationProvider}
      * instances registered with {@link DreamOverlayStateController}.
      */
-    public static class OverlayToken {
+    public static class ComplicationToken {
         private final int mId;
 
-        private OverlayToken(int id) {
+        private ComplicationToken(int id) {
             mId = id;
         }
 
         @Override
         public boolean equals(Object o) {
             if (this == o) return true;
-            if (!(o instanceof OverlayToken)) return false;
-            OverlayToken that = (OverlayToken) o;
+            if (!(o instanceof ComplicationToken)) return false;
+            ComplicationToken that = (ComplicationToken) o;
             return mId == that.mId;
         }
 
@@ -70,81 +76,97 @@
      */
     public interface Callback {
         /**
-         * Called when the visibility of the communal view changes.
+         * Called when the composition of complications changes.
          */
-        default void onOverlayChanged() {
+        default void onComplicationsChanged() {
         }
     }
 
+    private final Executor mExecutor;
     private final ArrayList<Callback> mCallbacks = new ArrayList<>();
-    private final HashMap<OverlayToken, OverlayProvider> mOverlays = new HashMap<>();
+    private final HashMap<ComplicationToken, ComplicationProvider> mComplications = new HashMap<>();
 
     @VisibleForTesting
     @Inject
-    public DreamOverlayStateController() {
+    public DreamOverlayStateController(@Main Executor executor) {
+        mExecutor = executor;
     }
 
     /**
-     * Adds an overlay to be presented on top of dreams.
-     * @param provider The {@link OverlayProvider} providing the dream.
-     * @return The {@link OverlayToken} tied to the supplied {@link OverlayProvider}.
+     * Adds a complication to be presented on top of dreams.
+     * @param provider The {@link ComplicationProvider} providing the dream.
+     * @return The {@link ComplicationToken} tied to the supplied {@link ComplicationProvider}.
      */
-    public OverlayToken addOverlay(OverlayProvider provider) {
-        final OverlayToken token = new OverlayToken(mNextOverlayTokenId++);
-        mOverlays.put(token, provider);
-        notifyCallbacks();
-        return token;
+    public ListenableFuture<ComplicationToken> addComplication(ComplicationProvider provider) {
+        return CallbackToFutureAdapter.getFuture(completer -> {
+            mExecutor.execute(() -> {
+                final ComplicationToken token = new ComplicationToken(mNextComplicationTokenId++);
+                mComplications.put(token, provider);
+                notifyCallbacks();
+                completer.set(token);
+            });
+            return "DreamOverlayStateController::addComplication";
+        });
     }
 
     /**
-     * Removes an overlay from being shown on dreams.
-     * @param token The {@link OverlayToken} associated with the {@link OverlayProvider} to be
-     *              removed.
-     * @return The removed {@link OverlayProvider}, {@code null} if not found.
+     * Removes a complication from being shown on dreams.
+     * @param token The {@link ComplicationToken} associated with the {@link ComplicationProvider}
+     *              to be removed.
+     * @return The removed {@link ComplicationProvider}, {@code null} if not found.
      */
-    public OverlayProvider removeOverlay(OverlayToken token) {
-        final OverlayProvider removedOverlay = mOverlays.remove(token);
+    public ListenableFuture<ComplicationProvider> removeComplication(ComplicationToken token) {
+        return CallbackToFutureAdapter.getFuture(completer -> {
+            mExecutor.execute(() -> {
+                final ComplicationProvider removedComplication = mComplications.remove(token);
 
-        if (removedOverlay != null) {
-            notifyCallbacks();
-        }
+                if (removedComplication != null) {
+                    notifyCallbacks();
+                }
+                completer.set(removedComplication);
+            });
 
-        return removedOverlay;
+            return "DreamOverlayStateController::removeComplication";
+        });
     }
 
     private void notifyCallbacks() {
         for (Callback callback : mCallbacks) {
-            callback.onOverlayChanged();
+            callback.onComplicationsChanged();
         }
     }
 
     @Override
     public void addCallback(@NonNull Callback callback) {
-        Objects.requireNonNull(callback, "Callback must not be null. b/128895449");
-        if (mCallbacks.contains(callback)) {
-            return;
-        }
+        mExecutor.execute(() -> {
+            Objects.requireNonNull(callback, "Callback must not be null. b/128895449");
+            if (mCallbacks.contains(callback)) {
+                return;
+            }
 
-        mCallbacks.add(callback);
+            mCallbacks.add(callback);
 
-        if (mOverlays.isEmpty()) {
-            return;
-        }
+            if (mComplications.isEmpty()) {
+                return;
+            }
 
-        callback.onOverlayChanged();
+            callback.onComplicationsChanged();
+        });
     }
 
     @Override
     public void removeCallback(@NonNull Callback callback) {
-        Objects.requireNonNull(callback, "Callback must not be null. b/128895449");
-        mCallbacks.remove(callback);
+        mExecutor.execute(() -> {
+            Objects.requireNonNull(callback, "Callback must not be null. b/128895449");
+            mCallbacks.remove(callback);
+        });
     }
 
     /**
-     * Returns all registered {@link OverlayProvider} instances.
-     * @return A collection of {@link OverlayProvider}.
+     * Returns all registered {@link ComplicationProvider} instances.
+     * @return A collection of {@link ComplicationProvider}.
      */
-    public Collection<OverlayProvider> getOverlays() {
-        return mOverlays.values();
+    public Collection<ComplicationProvider> getComplications() {
+        return mComplications.values();
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/OverlayHost.java b/packages/SystemUI/src/com/android/systemui/dreams/OverlayHost.java
deleted file mode 100644
index 08f0f35..0000000
--- a/packages/SystemUI/src/com/android/systemui/dreams/OverlayHost.java
+++ /dev/null
@@ -1,48 +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.dreams;
-
-import android.view.View;
-
-/**
- * A collection of interfaces related to hosting an overlay.
- */
-public abstract class OverlayHost {
-    /**
-     * An interface for the callback from the overlay provider to indicate when the overlay is
-     * ready.
-     */
-    public interface CreationCallback {
-        /**
-         * Called to inform the overlay view is ready to be placed within the visual space.
-         * @param view The view representing the overlay.
-         * @param layoutParams The parameters to create the view with.
-         */
-        void onCreated(View view, OverlayHostView.LayoutParams layoutParams);
-    }
-
-    /**
-     * An interface for the callback from the overlay provider to signal interactions in the
-     * overlay.
-     */
-    public interface InteractionCallback {
-        /**
-         * Called to signal the calling overlay would like to exit the dream.
-         */
-        void onExit();
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/OverlayProvider.java b/packages/SystemUI/src/com/android/systemui/dreams/OverlayProvider.java
deleted file mode 100644
index f208025..0000000
--- a/packages/SystemUI/src/com/android/systemui/dreams/OverlayProvider.java
+++ /dev/null
@@ -1,36 +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.dreams;
-
-import android.content.Context;
-
-/**
- * {@link OverlayProvider} is an interface for defining entities that can supply overlays to show
- * over a dream. Presentation components such as the {@link DreamOverlayService} supply
- * implementations with the necessary context for constructing such overlays.
- */
-public interface OverlayProvider {
-    /**
-     * Called when the {@link OverlayHost} requests the associated overlay be produced.
-     *
-     * @param context The {@link Context} used to construct the view.
-     * @param creationCallback The callback to inform when the overlay has been created.
-     * @param interactionCallback The callback to inform when the overlay has been interacted with.
-     */
-    void onCreateOverlay(Context context, OverlayHost.CreationCallback creationCallback,
-            OverlayHost.InteractionCallback interactionCallback);
-}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/appwidgets/AppWidgetProvider.java b/packages/SystemUI/src/com/android/systemui/dreams/appwidgets/AppWidgetProvider.java
index d1da1e6..687f7a2 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/appwidgets/AppWidgetProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/appwidgets/AppWidgetProvider.java
@@ -34,8 +34,8 @@
 
 /**
  * {@link AppWidgetProvider} is a singleton for accessing app widgets within SystemUI. This
- * consolidates resources such as the App Widget Host across potentially multiple
- * {@link AppWidgetOverlayProvider} instances and other usages.
+ * consolidates resources such as the {@link AppWidgetHost} across potentially multiple
+ * {@link ComplicationProvider} instances and other usages.
  */
 @SysUISingleton
 public class AppWidgetProvider {
@@ -87,8 +87,8 @@
                                 final float density = mResources.getDisplayMetrics().density;
                                 final int height = Math.round((bottom - top) / density);
                                 final int width = Math.round((right - left) / density);
-                                appWidgetView.updateAppWidgetSize(null, width, height, width,
-                                        height);
+                                appWidgetView.updateAppWidgetSize(null, width, height,
+                                        width, height);
                             });
                 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/appwidgets/AppWidgetOverlayPrimer.java b/packages/SystemUI/src/com/android/systemui/dreams/appwidgets/ComplicationPrimer.java
similarity index 65%
rename from packages/SystemUI/src/com/android/systemui/dreams/appwidgets/AppWidgetOverlayPrimer.java
rename to packages/SystemUI/src/com/android/systemui/dreams/appwidgets/ComplicationPrimer.java
index 563f707..7d30faf 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/appwidgets/AppWidgetOverlayPrimer.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/appwidgets/ComplicationPrimer.java
@@ -26,25 +26,25 @@
 import com.android.systemui.CoreStartable;
 import com.android.systemui.R;
 import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.dreams.ComplicationHostView;
 import com.android.systemui.dreams.DreamOverlayStateController;
-import com.android.systemui.dreams.OverlayHostView;
-import com.android.systemui.dreams.dagger.AppWidgetOverlayComponent;
+import com.android.systemui.dreams.appwidgets.dagger.AppWidgetComponent;
 
 import javax.inject.Inject;
 
 /**
- * {@link AppWidgetOverlayPrimer} reads the configured App Widget Overlay from resources on start
+ * {@link ComplicationPrimer} reads the configured AppWidget Complications from resources on start
  * and populates them into the {@link DreamOverlayStateController}.
  */
-public class AppWidgetOverlayPrimer extends CoreStartable {
+public class ComplicationPrimer extends CoreStartable {
     private final Resources mResources;
     private final DreamOverlayStateController mDreamOverlayStateController;
-    private final AppWidgetOverlayComponent.Factory mComponentFactory;
+    private final AppWidgetComponent.Factory mComponentFactory;
 
     @Inject
-    public AppWidgetOverlayPrimer(Context context, @Main Resources resources,
+    public ComplicationPrimer(Context context, @Main Resources resources,
             DreamOverlayStateController overlayStateController,
-            AppWidgetOverlayComponent.Factory appWidgetOverlayFactory) {
+            AppWidgetComponent.Factory appWidgetOverlayFactory) {
         super(context);
         mResources = resources;
         mDreamOverlayStateController = overlayStateController;
@@ -62,17 +62,18 @@
     }
 
     /**
-     * Generates the {@link OverlayHostView.LayoutParams} for a given gravity. Default dimension
-     * constraints are also included in the params.
+     * Generates the {@link ComplicationHostView.LayoutParams} for a given gravity. Default
+     * dimension constraints are also included in the params.
      * @param gravity The gravity for the layout as defined by {@link Gravity}.
      * @param resources The resourcs from which default dimensions will be extracted from.
-     * @return {@link OverlayHostView.LayoutParams} representing the provided gravity and default
-     * parameters.
+     * @return {@link ComplicationHostView.LayoutParams} representing the provided gravity and
+     *         default parameters.
      */
-    private static OverlayHostView.LayoutParams getLayoutParams(int gravity, Resources resources) {
-        final OverlayHostView.LayoutParams params = new OverlayHostView.LayoutParams(
-                OverlayHostView.LayoutParams.MATCH_CONSTRAINT,
-                OverlayHostView.LayoutParams.MATCH_CONSTRAINT);
+    private static ComplicationHostView.LayoutParams getLayoutParams(int gravity,
+            Resources resources) {
+        final ComplicationHostView.LayoutParams params = new ComplicationHostView.LayoutParams(
+                ComplicationHostView.LayoutParams.MATCH_CONSTRAINT,
+                ComplicationHostView.LayoutParams.MATCH_CONSTRAINT);
 
         if ((gravity & Gravity.BOTTOM) == Gravity.BOTTOM) {
             params.bottomToBottom = ConstraintSet.PARENT_ID;
@@ -92,28 +93,28 @@
 
         // For now, apply the same sizing constraints on every widget.
         params.matchConstraintPercentHeight =
-                resources.getFloat(R.dimen.config_dreamOverlayComponentHeightPercent);
+                resources.getFloat(R.dimen.config_dreamComplicationHeightPercent);
         params.matchConstraintPercentWidth =
-                resources.getFloat(R.dimen.config_dreamOverlayComponentWidthPercent);
+                resources.getFloat(R.dimen.config_dreamComplicationWidthPercent);
 
         return params;
     }
 
-
     /**
      * Helper method for loading widgets based on configuration.
      */
     private void loadDefaultWidgets() {
-        final int[] positions = mResources.getIntArray(R.array.config_dreamOverlayPositions);
+        final int[] positions = mResources.getIntArray(R.array.config_dreamComplicationPositions);
         final String[] components =
-                mResources.getStringArray(R.array.config_dreamOverlayComponents);
+                mResources.getStringArray(R.array.config_dreamAppWidgetComplications);
 
         for (int i = 0; i < Math.min(positions.length, components.length); i++) {
-            final AppWidgetOverlayComponent component = mComponentFactory.build(
+            final AppWidgetComponent component = mComponentFactory.build(
                     ComponentName.unflattenFromString(components[i]),
                     getLayoutParams(positions[i], mResources));
 
-            mDreamOverlayStateController.addOverlay(component.getAppWidgetOverlayProvider());
+            mDreamOverlayStateController.addComplication(
+                    component.getAppWidgetComplicationProvider());
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/appwidgets/AppWidgetOverlayProvider.java b/packages/SystemUI/src/com/android/systemui/dreams/appwidgets/ComplicationProvider.java
similarity index 74%
rename from packages/SystemUI/src/com/android/systemui/dreams/appwidgets/AppWidgetOverlayProvider.java
rename to packages/SystemUI/src/com/android/systemui/dreams/appwidgets/ComplicationProvider.java
index a635d3f..9188ee5 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/appwidgets/AppWidgetOverlayProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/appwidgets/ComplicationProvider.java
@@ -22,30 +22,30 @@
 import android.util.Log;
 import android.widget.RemoteViews;
 
-import com.android.systemui.dreams.OverlayHost;
-import com.android.systemui.dreams.OverlayHostView;
-import com.android.systemui.dreams.OverlayProvider;
+import com.android.systemui.dreams.ComplicationHost;
+import com.android.systemui.dreams.ComplicationHostView;
 import com.android.systemui.plugins.ActivityStarter;
 
 import javax.inject.Inject;
 
 /**
- * {@link AppWidgetOverlayProvider} is an implementation of {@link OverlayProvider} for providing
- * app widget-based overlays.
+ * {@link ComplicationProvider} is an implementation of
+ * {@link com.android.systemui.dreams.ComplicationProvider} for providing app widget-based
+ * complications.
  */
-public class AppWidgetOverlayProvider implements OverlayProvider {
-    private static final String TAG = "AppWdgtOverlayProvider";
+public class ComplicationProvider implements com.android.systemui.dreams.ComplicationProvider {
+    private static final String TAG = "AppWidgetCompProvider";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
     private final ActivityStarter mActivityStarter;
     private final AppWidgetProvider mAppWidgetProvider;
     private final ComponentName mComponentName;
-    private final OverlayHostView.LayoutParams mLayoutParams;
+    private final ComplicationHostView.LayoutParams mLayoutParams;
 
     @Inject
-    public AppWidgetOverlayProvider(ActivityStarter activityStarter,
+    public ComplicationProvider(ActivityStarter activityStarter,
             ComponentName componentName, AppWidgetProvider widgetProvider,
-            OverlayHostView.LayoutParams layoutParams) {
+            ComplicationHostView.LayoutParams layoutParams) {
         mActivityStarter = activityStarter;
         mComponentName = componentName;
         mAppWidgetProvider = widgetProvider;
@@ -53,8 +53,9 @@
     }
 
     @Override
-    public void onCreateOverlay(Context context, OverlayHost.CreationCallback creationCallback,
-            OverlayHost.InteractionCallback interactionCallback) {
+    public void onCreateComplication(Context context,
+            ComplicationHost.CreationCallback creationCallback,
+            ComplicationHost.InteractionCallback interactionCallback) {
         final AppWidgetHostView widget = mAppWidgetProvider.getWidget(mComponentName);
 
         if (widget == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/dagger/AppWidgetOverlayComponent.java b/packages/SystemUI/src/com/android/systemui/dreams/appwidgets/dagger/AppWidgetComponent.java
similarity index 62%
rename from packages/SystemUI/src/com/android/systemui/dreams/dagger/AppWidgetOverlayComponent.java
rename to packages/SystemUI/src/com/android/systemui/dreams/appwidgets/dagger/AppWidgetComponent.java
index 3103057..7beed17 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/dagger/AppWidgetOverlayComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/appwidgets/dagger/AppWidgetComponent.java
@@ -14,26 +14,26 @@
  * limitations under the License.
  */
 
-package com.android.systemui.dreams.dagger;
+package com.android.systemui.dreams.appwidgets.dagger;
 
 import android.content.ComponentName;
 
-import com.android.systemui.dreams.OverlayHostView;
-import com.android.systemui.dreams.appwidgets.AppWidgetOverlayProvider;
+import com.android.systemui.dreams.ComplicationHostView;
+import com.android.systemui.dreams.appwidgets.ComplicationProvider;
 
 import dagger.BindsInstance;
 import dagger.Subcomponent;
 
 /** */
 @Subcomponent
-public interface AppWidgetOverlayComponent {
+public interface AppWidgetComponent {
     /** */
     @Subcomponent.Factory
     interface Factory {
-        AppWidgetOverlayComponent build(@BindsInstance ComponentName component,
-                @BindsInstance OverlayHostView.LayoutParams layoutParams);
+        AppWidgetComponent build(@BindsInstance ComponentName component,
+                @BindsInstance ComplicationHostView.LayoutParams layoutParams);
     }
 
-    /** Builds a {@link AppWidgetOverlayProvider}. */
-    AppWidgetOverlayProvider getAppWidgetOverlayProvider();
+    /** Builds a {@link ComplicationProvider}. */
+    ComplicationProvider getAppWidgetComplicationProvider();
 }
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java
index ff5beb5..0d4688e 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java
@@ -16,11 +16,15 @@
 
 package com.android.systemui.dreams.dagger;
 
+import com.android.systemui.dreams.appwidgets.dagger.AppWidgetComponent;
+
 import dagger.Module;
 
 /**
  * Dagger Module providing Communal-related functionality.
  */
-@Module(subcomponents = {AppWidgetOverlayComponent.class, DreamOverlayComponent.class})
+@Module(subcomponents = {
+        AppWidgetComponent.class,
+        DreamOverlayComponent.class})
 public interface DreamModule {
 }
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayComponent.java b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayComponent.java
index a3a446a..c90332b 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayComponent.java
@@ -18,10 +18,7 @@
 
 import static java.lang.annotation.RetentionPolicy.RUNTIME;
 
-import android.view.ViewGroup;
-
-import com.android.systemui.dreams.DreamOverlayContainerView;
-import com.android.systemui.dreams.DreamOverlayStatusBarViewController;
+import com.android.systemui.dreams.DreamOverlayContainerViewController;
 
 import java.lang.annotation.Documented;
 import java.lang.annotation.Retention;
@@ -48,15 +45,7 @@
     @Scope
     @interface DreamOverlayScope {}
 
-    /** Builds a {@link DreamOverlayContainerView} */
+    /** Builds a {@link DreamOverlayContainerViewController}. */
     @DreamOverlayScope
-    DreamOverlayContainerView getDreamOverlayContainerView();
-
-    /** Builds a content view for dream overlays */
-    @DreamOverlayScope
-    ViewGroup getDreamOverlayContentView();
-
-    /** Builds a {@link DreamOverlayStatusBarViewController}. */
-    @DreamOverlayScope
-    DreamOverlayStatusBarViewController getDreamOverlayStatusBarViewController();
+    DreamOverlayContainerViewController getDreamOverlayContainerViewController();
 }
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java
index d0a8fad..5b588a9 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java
@@ -44,6 +44,7 @@
     private static final String DREAM_OVERLAY_BATTERY_VIEW = "dream_overlay_battery_view";
     public static final String DREAM_OVERLAY_BATTERY_CONTROLLER =
             "dream_overlay_battery_controller";
+    public static final String DREAM_OVERLAY_CONTENT_VIEW = "dream_overlay_content_view";
 
     /** */
     @Provides
@@ -58,6 +59,7 @@
     /** */
     @Provides
     @DreamOverlayComponent.DreamOverlayScope
+    @Named(DREAM_OVERLAY_CONTENT_VIEW)
     public static ViewGroup providesDreamOverlayContentView(DreamOverlayContainerView view) {
         return Preconditions.checkNotNull(view.findViewById(R.id.dream_overlay_content),
                 "R.id.dream_overlay_content must not be null");
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.java b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
index 4e852a8..726f865 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
@@ -43,15 +43,18 @@
     public static final BooleanFlag NEW_NOTIFICATION_PIPELINE_RENDERING =
             new BooleanFlag(101, false);
 
-    public static final BooleanFlag NOTIFICATION_UPDATES =
-            new BooleanFlag(102, true);
-
     public static final BooleanFlag NOTIFICATION_PIPELINE_DEVELOPER_LOGGING =
             new BooleanFlag(103, false);
 
     public static final ResourceBooleanFlag NOTIFICATION_SHADE_DRAG =
             new ResourceBooleanFlag(104, R.bool.config_enableNotificationShadeDrag);
 
+    public static final BooleanFlag NSSL_DEBUG_LINES =
+            new BooleanFlag(105, false);
+
+    public static final BooleanFlag NSSL_DEBUG_REMOVE_ANIMATION =
+            new BooleanFlag(106, false);
+
     /***************************************/
     // 200 - keyguard/lockscreen
     public static final BooleanFlag KEYGUARD_LAYOUT =
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardLifecyclesDispatcher.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardLifecyclesDispatcher.java
index 5019e65..32b58c2 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardLifecyclesDispatcher.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardLifecyclesDispatcher.java
@@ -19,7 +19,10 @@
 import android.os.Handler;
 import android.os.Message;
 import android.os.PowerManager;
+import android.os.RemoteException;
+import android.util.Log;
 
+import com.android.internal.policy.IKeyguardDrawnCallback;
 import com.android.systemui.dagger.SysUISingleton;
 
 import javax.inject.Inject;
@@ -39,6 +42,7 @@
     static final int FINISHED_WAKING_UP = 5;
     static final int STARTED_GOING_TO_SLEEP = 6;
     static final int FINISHED_GOING_TO_SLEEP = 7;
+    private static final String TAG = "KeyguardLifecyclesDispatcher";
 
     private final ScreenLifecycle mScreenLifecycle;
     private final WakefulnessLifecycle mWakefulnessLifecycle;
@@ -65,12 +69,38 @@
         message.sendToTarget();
     }
 
+    /**
+     * @param what Message to send.
+     * @param object Object to send with the message
+     */
+    void dispatch(int what, Object object) {
+        mHandler.obtainMessage(what, object).sendToTarget();
+    }
+
     private Handler mHandler = new Handler() {
         @Override
         public void handleMessage(Message msg) {
+            final Object obj = msg.obj;
             switch (msg.what) {
                 case SCREEN_TURNING_ON:
-                    mScreenLifecycle.dispatchScreenTurningOn();
+                    // Ensure the drawn callback is only ever called once
+                    mScreenLifecycle.dispatchScreenTurningOn(new Runnable() {
+                            boolean mInvoked;
+                            @Override
+                            public void run() {
+                                if (obj == null) return;
+                                if (!mInvoked) {
+                                    mInvoked = true;
+                                    try {
+                                        ((IKeyguardDrawnCallback) obj).onDrawn();
+                                    } catch (RemoteException e) {
+                                        Log.w(TAG, "Exception calling onDrawn():", e);
+                                    }
+                                } else {
+                                    Log.w(TAG, "KeyguardDrawnCallback#onDrawn() invoked > 1 times");
+                                }
+                            }
+                        });
                     break;
                 case SCREEN_TURNED_ON:
                     mScreenLifecycle.dispatchScreenTurnedOn();
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index 22a69d4..e88011e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@@ -500,8 +500,8 @@
         public void onScreenTurningOn(IKeyguardDrawnCallback callback) {
             Trace.beginSection("KeyguardService.mBinder#onScreenTurningOn");
             checkPermission();
-            mKeyguardViewMediator.onScreenTurningOn(callback);
-            mKeyguardLifecyclesDispatcher.dispatch(KeyguardLifecyclesDispatcher.SCREEN_TURNING_ON);
+            mKeyguardLifecyclesDispatcher.dispatch(KeyguardLifecyclesDispatcher.SCREEN_TURNING_ON,
+                    callback);
             Trace.endSection();
         }
 
@@ -509,7 +509,6 @@
         public void onScreenTurnedOn() {
             Trace.beginSection("KeyguardService.mBinder#onScreenTurnedOn");
             checkPermission();
-            mKeyguardViewMediator.onScreenTurnedOn();
             mKeyguardLifecyclesDispatcher.dispatch(KeyguardLifecyclesDispatcher.SCREEN_TURNED_ON);
             Trace.endSection();
         }
@@ -583,6 +582,18 @@
             checkPermission();
             mKeyguardViewMediator.onShortPowerPressedGoHome();
         }
+
+        @Override
+        public void dismissKeyguardToLaunch(Intent intentToLaunch) {
+            checkPermission();
+            mKeyguardViewMediator.dismissKeyguardToLaunch(intentToLaunch);
+        }
+
+        @Override
+        public void onSystemKeyPressed(int keycode) {
+            checkPermission();
+            mKeyguardViewMediator.onSystemKeyPressed(keycode);
+        }
     };
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 0512d48..4658a74 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -87,7 +87,6 @@
 import com.android.internal.jank.InteractionJankMonitor;
 import com.android.internal.jank.InteractionJankMonitor.Configuration;
 import com.android.internal.policy.IKeyguardDismissCallback;
-import com.android.internal.policy.IKeyguardDrawnCallback;
 import com.android.internal.policy.IKeyguardExitCallback;
 import com.android.internal.policy.IKeyguardStateCallback;
 import com.android.internal.util.LatencyTracker;
@@ -99,6 +98,7 @@
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.keyguard.KeyguardViewController;
 import com.android.keyguard.ViewMediatorCallback;
+import com.android.keyguard.mediator.ScreenOnCoordinator;
 import com.android.systemui.CoreStartable;
 import com.android.systemui.Dumpable;
 import com.android.systemui.animation.Interpolators;
@@ -122,15 +122,11 @@
 import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
-import com.android.systemui.unfold.FoldAodAnimationController;
-import com.android.systemui.unfold.SysUIUnfoldComponent;
-import com.android.systemui.unfold.UnfoldLightRevealOverlayAnimation;
 import com.android.systemui.util.DeviceConfigProxy;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
-import java.util.Optional;
 import java.util.concurrent.Executor;
 
 import dagger.Lazy;
@@ -146,7 +142,7 @@
  * so that once the screen comes on, it will be ready immediately.
  *
  * Example queries about the keyguard:
- * - is {movement, key} one that should wake the keygaurd?
+ * - is {movement, key} one that should wake the keyguard?
  * - is the keyguard showing?
  * - are input events restricted due to the state of the keyguard?
  *
@@ -199,7 +195,6 @@
     private static final int RESET = 3;
     private static final int VERIFY_UNLOCK = 4;
     private static final int NOTIFY_FINISHED_GOING_TO_SLEEP = 5;
-    private static final int NOTIFY_SCREEN_TURNING_ON = 6;
     private static final int KEYGUARD_DONE = 7;
     private static final int KEYGUARD_DONE_DRAWING = 8;
     private static final int SET_OCCLUDED = 9;
@@ -208,8 +203,6 @@
     private static final int START_KEYGUARD_EXIT_ANIM = 12;
     private static final int KEYGUARD_DONE_PENDING_TIMEOUT = 13;
     private static final int NOTIFY_STARTED_WAKING_UP = 14;
-    private static final int NOTIFY_SCREEN_TURNED_ON = 15;
-    private static final int NOTIFY_SCREEN_TURNED_OFF = 16;
     private static final int NOTIFY_STARTED_GOING_TO_SLEEP = 17;
     private static final int SYSTEM_READY = 18;
     private static final int CANCEL_KEYGUARD_EXIT_ANIM = 19;
@@ -429,17 +422,10 @@
      */
     private WorkLockActivityController mWorkLockController;
 
-    /**
-     * @see #setPulsing(boolean)
-     */
-    private boolean mPulsing;
-
     private boolean mLockLater;
     private boolean mShowHomeOverLockscreen;
     private boolean mInGestureNavigationMode;
 
-    private boolean mWakeAndUnlocking;
-    private Runnable mWakeAndUnlockingDrawnCallback;
     private CharSequence mCustomMessage;
 
     /**
@@ -816,14 +802,11 @@
     private DeviceConfigProxy mDeviceConfig;
     private DozeParameters mDozeParameters;
 
-    private final Optional<UnfoldLightRevealOverlayAnimation> mUnfoldLightRevealAnimation;
-    private final Optional<FoldAodAnimationController> mFoldAodAnimationController;
-    private final PendingDrawnTasksContainer mPendingDrawnTasks = new PendingDrawnTasksContainer();
-
     private final KeyguardStateController mKeyguardStateController;
     private final Lazy<KeyguardUnlockAnimationController> mKeyguardUnlockAnimationControllerLazy;
     private final InteractionJankMonitor mInteractionJankMonitor;
     private boolean mWallpaperSupportsAmbientMode;
+    private ScreenOnCoordinator mScreenOnCoordinator;
 
     /**
      * Injected constructor. See {@link KeyguardModule}.
@@ -843,12 +826,12 @@
             NavigationModeController navigationModeController,
             KeyguardDisplayManager keyguardDisplayManager,
             DozeParameters dozeParameters,
-            Optional<SysUIUnfoldComponent> unfoldComponent,
             SysuiStatusBarStateController statusBarStateController,
             KeyguardStateController keyguardStateController,
             Lazy<KeyguardUnlockAnimationController> keyguardUnlockAnimationControllerLazy,
             ScreenOffAnimationController screenOffAnimationController,
             Lazy<NotificationShadeDepthController> notificationShadeDepthController,
+            ScreenOnCoordinator screenOnCoordinator,
             InteractionJankMonitor interactionJankMonitor) {
         super(context);
         mFalsingCollector = falsingCollector;
@@ -865,6 +848,7 @@
         mKeyguardDisplayManager = keyguardDisplayManager;
         dumpManager.registerDumpable(getClass().getName(), this);
         mDeviceConfig = deviceConfig;
+        mScreenOnCoordinator = screenOnCoordinator;
         mShowHomeOverLockscreen = mDeviceConfig.getBoolean(
                 DeviceConfig.NAMESPACE_SYSTEMUI,
                 NAV_BAR_HANDLE_SHOW_OVER_LOCKSCREEN,
@@ -879,11 +863,6 @@
                 }));
         mDozeParameters = dozeParameters;
 
-        mUnfoldLightRevealAnimation = unfoldComponent
-                .map(SysUIUnfoldComponent::getUnfoldLightRevealOverlayAnimation);
-        mFoldAodAnimationController = unfoldComponent
-                .map(SysUIUnfoldComponent::getFoldAodAnimationController);
-
         mStatusBarStateController = statusBarStateController;
         statusBarStateController.addCallback(this);
 
@@ -1076,7 +1055,7 @@
         synchronized (this) {
             mDeviceInteractive = false;
             mGoingToSleep = false;
-            mWakeAndUnlocking = false;
+            mScreenOnCoordinator.setWakeAndUnlocking(false);
             mAnimatingScreenOff = mDozeParameters.shouldAnimateDozingChange();
 
             resetKeyguardDonePendingLocked();
@@ -1254,21 +1233,7 @@
         Trace.endSection();
     }
 
-    public void onScreenTurningOn(IKeyguardDrawnCallback callback) {
-        Trace.beginSection("KeyguardViewMediator#onScreenTurningOn");
-        notifyScreenOn(callback);
-        Trace.endSection();
-    }
-
-    public void onScreenTurnedOn() {
-        Trace.beginSection("KeyguardViewMediator#onScreenTurnedOn");
-        notifyScreenTurnedOn();
-        mUpdateMonitor.dispatchScreenTurnedOn();
-        Trace.endSection();
-    }
-
     public void onScreenTurnedOff() {
-        notifyScreenTurnedOff();
         mUpdateMonitor.dispatchScreenTurnedOff();
     }
 
@@ -1283,7 +1248,7 @@
             // Skipping the lockscreen because we're not yet provisioned, but we still need to
             // notify the StrongAuthTracker that it's now safe to run trust agents, in case the
             // user sets a credential later.
-            getLockPatternUtils().userPresent(KeyguardUpdateMonitor.getCurrentUser());
+            mLockPatternUtils.userPresent(KeyguardUpdateMonitor.getCurrentUser());
         }
     }
 
@@ -1660,24 +1625,6 @@
         mHandler.sendEmptyMessage(NOTIFY_STARTED_WAKING_UP);
     }
 
-    private void notifyScreenOn(IKeyguardDrawnCallback callback) {
-        if (DEBUG) Log.d(TAG, "notifyScreenOn");
-        Message msg = mHandler.obtainMessage(NOTIFY_SCREEN_TURNING_ON, callback);
-        mHandler.sendMessage(msg);
-    }
-
-    private void notifyScreenTurnedOn() {
-        if (DEBUG) Log.d(TAG, "notifyScreenTurnedOn");
-        Message msg = mHandler.obtainMessage(NOTIFY_SCREEN_TURNED_ON);
-        mHandler.sendMessage(msg);
-    }
-
-    private void notifyScreenTurnedOff() {
-        if (DEBUG) Log.d(TAG, "notifyScreenTurnedOff");
-        Message msg = mHandler.obtainMessage(NOTIFY_SCREEN_TURNED_OFF);
-        mHandler.sendMessage(msg);
-    }
-
     /**
      * Send message to keyguard telling it to show itself
      * @see #handleShow
@@ -1838,21 +1785,6 @@
                 case NOTIFY_FINISHED_GOING_TO_SLEEP:
                     handleNotifyFinishedGoingToSleep();
                     break;
-                case NOTIFY_SCREEN_TURNING_ON:
-                    Trace.beginSection(
-                            "KeyguardViewMediator#handleMessage NOTIFY_SCREEN_TURNING_ON");
-                    handleNotifyScreenTurningOn((IKeyguardDrawnCallback) msg.obj);
-                    Trace.endSection();
-                    break;
-                case NOTIFY_SCREEN_TURNED_ON:
-                    Trace.beginSection(
-                            "KeyguardViewMediator#handleMessage NOTIFY_SCREEN_TURNED_ON");
-                    handleNotifyScreenTurnedOn();
-                    Trace.endSection();
-                    break;
-                case NOTIFY_SCREEN_TURNED_OFF:
-                    handleNotifyScreenTurnedOff();
-                    break;
                 case NOTIFY_STARTED_WAKING_UP:
                     Trace.beginSection(
                             "KeyguardViewMediator#handleMessage NOTIFY_STARTED_WAKING_UP");
@@ -1984,7 +1916,7 @@
                     for (int profileId : um.getProfileIdsWithDisabled(currentUser.getIdentifier())) {
                         mContext.sendBroadcastAsUser(USER_PRESENT_INTENT, UserHandle.of(profileId));
                     }
-                    getLockPatternUtils().userPresent(currentUserId);
+                    mLockPatternUtils.userPresent(currentUserId);
                 });
             } else {
                 mBootSendUserPresent = true;
@@ -2081,7 +2013,7 @@
 
             mHiding = false;
             mKeyguardExitAnimationRunner = null;
-            mWakeAndUnlocking = false;
+            mScreenOnCoordinator.setWakeAndUnlocking(false);
             mPendingLock = false;
             setShowingLocked(true);
             mKeyguardViewControllerLazy.get().show(options);
@@ -2113,12 +2045,14 @@
 
             int flags = 0;
             if (mKeyguardViewControllerLazy.get().shouldDisableWindowAnimationsForUnlock()
-                    || mWakeAndUnlocking && !mWallpaperSupportsAmbientMode) {
+                    || mScreenOnCoordinator.getWakeAndUnlocking()
+                            && !mWallpaperSupportsAmbientMode) {
                 flags |= WindowManagerPolicyConstants
                         .KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS;
             }
             if (mKeyguardViewControllerLazy.get().isGoingToNotificationShade()
-                    || mWakeAndUnlocking && mWallpaperSupportsAmbientMode) {
+                    || mScreenOnCoordinator.getWakeAndUnlocking()
+                            && mWallpaperSupportsAmbientMode) {
                 // When the wallpaper supports ambient mode, the scrim isn't fully opaque during
                 // wake and unlock and we should fade in the app on top of the wallpaper
                 flags |= WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_TO_SHADE;
@@ -2229,14 +2163,13 @@
             IRemoteAnimationRunner runner = mKeyguardExitAnimationRunner;
             mKeyguardExitAnimationRunner = null;
 
-            if (mWakeAndUnlocking && mWakeAndUnlockingDrawnCallback != null) {
+            if (mScreenOnCoordinator.getWakeAndUnlocking()) {
 
                 // Hack level over 9000: To speed up wake-and-unlock sequence, force it to report
                 // the next draw from here so we don't have to wait for window manager to signal
                 // this to our ViewRootImpl.
                 mKeyguardViewControllerLazy.get().getViewRootImpl().setReportNextDraw();
-                mWakeAndUnlockingDrawnCallback.run();
-                mWakeAndUnlockingDrawnCallback = null;
+                mScreenOnCoordinator.setWakeAndUnlocking(false);
             }
 
             LatencyTracker.getInstance(mContext)
@@ -2360,7 +2293,7 @@
         }
 
         setShowingLocked(false);
-        mWakeAndUnlocking = false;
+        mScreenOnCoordinator.setWakeAndUnlocking(false);
         mDismissCallbackRegistry.notifyDismissSucceeded();
         resetKeyguardDonePendingLocked();
         mHideAnimationRun = false;
@@ -2567,66 +2500,6 @@
         Trace.endSection();
     }
 
-    private void handleNotifyScreenTurningOn(IKeyguardDrawnCallback callback) {
-        Trace.beginSection("KeyguardViewMediator#handleNotifyScreenTurningOn");
-        synchronized (KeyguardViewMediator.this) {
-            if (DEBUG) Log.d(TAG, "handleNotifyScreenTurningOn");
-
-            mPendingDrawnTasks.reset();
-
-            if (mUnfoldLightRevealAnimation.isPresent()) {
-                mUnfoldLightRevealAnimation.get()
-                        .onScreenTurningOn(mPendingDrawnTasks.registerTask("unfold-reveal"));
-            }
-
-            if (mFoldAodAnimationController.isPresent()) {
-                mFoldAodAnimationController.get()
-                        .onScreenTurningOn(mPendingDrawnTasks.registerTask("fold-to-aod"));
-            }
-
-            mKeyguardViewControllerLazy.get().onScreenTurningOn();
-            if (callback != null) {
-                if (mWakeAndUnlocking) {
-                    mWakeAndUnlockingDrawnCallback =
-                            mPendingDrawnTasks.registerTask("wake-and-unlocking");
-                }
-            }
-
-            mPendingDrawnTasks.onTasksComplete(() -> notifyDrawn(callback));
-        }
-        Trace.endSection();
-    }
-
-    private void handleNotifyScreenTurnedOn() {
-        Trace.beginSection("KeyguardViewMediator#handleNotifyScreenTurnedOn");
-        synchronized (this) {
-            if (DEBUG) Log.d(TAG, "handleNotifyScreenTurnedOn");
-
-            mPendingDrawnTasks.reset();
-            mKeyguardViewControllerLazy.get().onScreenTurnedOn();
-        }
-        Trace.endSection();
-    }
-
-    private void handleNotifyScreenTurnedOff() {
-        synchronized (this) {
-            if (DEBUG) Log.d(TAG, "handleNotifyScreenTurnedOff");
-            mWakeAndUnlockingDrawnCallback = null;
-        }
-    }
-
-    private void notifyDrawn(final IKeyguardDrawnCallback callback) {
-        Trace.beginSection("KeyguardViewMediator#notifyDrawn");
-        try {
-            if (callback != null) {
-                callback.onDrawn();
-            }
-        } catch (RemoteException e) {
-            Slog.w(TAG, "Exception calling onDrawn():", e);
-        }
-        Trace.endSection();
-    }
-
     private void resetKeyguardDonePendingLocked() {
         mKeyguardDonePending = false;
         mHandler.removeMessages(KEYGUARD_DONE_PENDING_TIMEOUT);
@@ -2650,7 +2523,7 @@
 
     public void onWakeAndUnlocking() {
         Trace.beginSection("KeyguardViewMediator#onWakeAndUnlocking");
-        mWakeAndUnlocking = true;
+        mScreenOnCoordinator.setWakeAndUnlocking(true);
         keyguardDone();
         Trace.endSection();
     }
@@ -2750,12 +2623,16 @@
         // do nothing
     }
 
-    public ViewMediatorCallback getViewMediatorCallback() {
-        return mViewMediatorCallback;
+    public void dismissKeyguardToLaunch(Intent intentToLaunch) {
+        // do nothing
     }
 
-    public LockPatternUtils getLockPatternUtils() {
-        return mLockPatternUtils;
+    public void onSystemKeyPressed(int keycode) {
+        // do nothing
+    }
+
+    public ViewMediatorCallback getViewMediatorCallback() {
+        return mViewMediatorCallback;
     }
 
     @Override
@@ -2781,9 +2658,7 @@
         pw.print("  mHideAnimationRun: "); pw.println(mHideAnimationRun);
         pw.print("  mPendingReset: "); pw.println(mPendingReset);
         pw.print("  mPendingLock: "); pw.println(mPendingLock);
-        pw.print("  mPendingDrawnTasks: "); pw.println(mPendingDrawnTasks.getPendingCount());
-        pw.print("  mWakeAndUnlocking: "); pw.println(mWakeAndUnlocking);
-        pw.print("  mDrawnCallback: "); pw.println(mWakeAndUnlockingDrawnCallback);
+        pw.print("  wakeAndUnlocking: "); pw.println(mScreenOnCoordinator.getWakeAndUnlocking());
     }
 
     /**
@@ -2819,13 +2694,6 @@
     }
 
     /**
-     * @param pulsing true when device temporarily wakes up to display an incoming notification.
-     */
-    public void setPulsing(boolean pulsing) {
-        mPulsing = pulsing;
-    }
-
-    /**
      * Set if the wallpaper supports ambient mode. This is used to trigger the right animation.
      * In case it does support it, we have to fade in the incoming app, otherwise we'll reveal it
      * with the light reveal scrim.
@@ -2864,7 +2732,7 @@
     }
 
     private void setShowingLocked(boolean showing, boolean forceCallbacks) {
-        final boolean aodShowing = mDozing && !mWakeAndUnlocking;
+        final boolean aodShowing = mDozing && !mScreenOnCoordinator.getWakeAndUnlocking();
         final boolean notifyDefaultDisplayCallbacks = showing != mShowing
                 || aodShowing != mAodShowing || forceCallbacks;
         mShowing = showing;
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/Lifecycle.java b/packages/SystemUI/src/com/android/systemui/keyguard/Lifecycle.java
index 3da6caf..b870f58 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/Lifecycle.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/Lifecycle.java
@@ -20,6 +20,7 @@
 
 import java.util.ArrayList;
 import java.util.Objects;
+import java.util.function.BiConsumer;
 import java.util.function.Consumer;
 
 /**
@@ -42,4 +43,13 @@
             consumer.accept(mObservers.get(i));
         }
     }
+
+    /**
+     * Will dispatch the consumer to the observer, along with a single argument of type<U>.
+     */
+    public <U> void dispatch(BiConsumer<T, U> biConsumer, U arg) {
+        for (int i = 0; i < mObservers.size(); i++) {
+            biConsumer.accept(mObservers.get(i), arg);
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ScreenLifecycle.java b/packages/SystemUI/src/com/android/systemui/keyguard/ScreenLifecycle.java
index d17c39a..e71aa85 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ScreenLifecycle.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ScreenLifecycle.java
@@ -18,6 +18,8 @@
 
 import android.os.Trace;
 
+import androidx.annotation.NonNull;
+
 import com.android.systemui.Dumpable;
 import com.android.systemui.dump.DumpManager;
 
@@ -49,9 +51,14 @@
         return mScreenState;
     }
 
-    public void dispatchScreenTurningOn() {
+    /**
+     * Dispatch screen turning on events to the registered observers
+     *
+     * @param onDrawn Invoke to notify the caller that the event has been processed
+     */
+    public void dispatchScreenTurningOn(@NonNull Runnable onDrawn) {
         setScreenState(SCREEN_TURNING_ON);
-        dispatch(Observer::onScreenTurningOn);
+        dispatch(Observer::onScreenTurningOn, onDrawn);
     }
 
     public void dispatchScreenTurnedOn() {
@@ -81,7 +88,12 @@
     }
 
     public interface Observer {
-        default void onScreenTurningOn() {}
+        /**
+         * Receive the screen turning on event
+         *
+         * @param onDrawn Invoke to notify the caller that the event has been processed
+         */
+        default void onScreenTurningOn(@NonNull Runnable onDrawn) {}
         default void onScreenTurnedOn() {}
         default void onScreenTurningOff() {}
         default void onScreenTurnedOff() {}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
index eecb55b..dd844e8d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
@@ -31,6 +31,7 @@
 import com.android.keyguard.dagger.KeyguardStatusBarViewComponent;
 import com.android.keyguard.dagger.KeyguardStatusViewComponent;
 import com.android.keyguard.dagger.KeyguardUserSwitcherComponent;
+import com.android.keyguard.mediator.ScreenOnCoordinator;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.classifier.FalsingModule;
@@ -50,11 +51,9 @@
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
-import com.android.systemui.unfold.SysUIUnfoldComponent;
 import com.android.systemui.util.DeviceConfigProxy;
 import com.android.systemui.util.sensors.AsyncSensorManager;
 
-import java.util.Optional;
 import java.util.concurrent.Executor;
 
 import dagger.Lazy;
@@ -93,12 +92,12 @@
             NavigationModeController navigationModeController,
             KeyguardDisplayManager keyguardDisplayManager,
             DozeParameters dozeParameters,
-            Optional<SysUIUnfoldComponent> unfoldComponent,
             SysuiStatusBarStateController statusBarStateController,
             KeyguardStateController keyguardStateController,
             Lazy<KeyguardUnlockAnimationController> keyguardUnlockAnimationController,
             ScreenOffAnimationController screenOffAnimationController,
             Lazy<NotificationShadeDepthController> notificationShadeDepthController,
+            ScreenOnCoordinator screenOnCoordinator,
             InteractionJankMonitor interactionJankMonitor) {
         return new KeyguardViewMediator(
                 context,
@@ -117,12 +116,12 @@
                 navigationModeController,
                 keyguardDisplayManager,
                 dozeParameters,
-                unfoldComponent,
                 statusBarStateController,
                 keyguardStateController,
                 keyguardUnlockAnimationController,
                 screenOffAnimationController,
                 notificationShadeDepthController,
+                screenOnCoordinator,
                 interactionJankMonitor
         );
     }
diff --git a/packages/SystemUI/src/com/android/systemui/log/LogBuffer.kt b/packages/SystemUI/src/com/android/systemui/log/LogBuffer.kt
index 492fdc6..b15807c 100644
--- a/packages/SystemUI/src/com/android/systemui/log/LogBuffer.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/LogBuffer.kt
@@ -66,11 +66,12 @@
  * @param poolSize The maximum amount that the size of the buffer is allowed to flex in response to
  * sequential calls to [document] that aren't immediately followed by a matching call to [push].
  */
-class LogBuffer(
+class LogBuffer @JvmOverloads constructor(
     private val name: String,
     private val maxLogs: Int,
     private val poolSize: Int,
-    private val logcatEchoTracker: LogcatEchoTracker
+    private val logcatEchoTracker: LogcatEchoTracker,
+    private val systrace: Boolean = true
 ) {
     init {
         if (maxLogs < poolSize) {
@@ -175,6 +176,10 @@
             buffer.removeFirst()
         }
         buffer.add(message as LogMessageImpl)
+        if (systrace) {
+            val messageStr = message.printer(message)
+            Trace.instantForTrack(Trace.TRACE_TAG_APP, "UI Events", "$name - $messageStr")
+        }
         if (logcatEchoTracker.isBufferLoggable(name, message.level) ||
                 logcatEchoTracker.isTagLoggable(message.tag, message.level)) {
             echo(message)
@@ -237,7 +242,6 @@
             LogLevel.ERROR -> Log.e(message.tag, strMessage)
             LogLevel.WTF -> Log.wtf(message.tag, strMessage)
         }
-        Trace.instantForTrack(Trace.TRACE_TAG_APP, "UI Events", strMessage)
     }
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/log/LogBufferFactory.kt b/packages/SystemUI/src/com/android/systemui/log/LogBufferFactory.kt
index 5296ee6..cbfca25 100644
--- a/packages/SystemUI/src/com/android/systemui/log/LogBufferFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/LogBufferFactory.kt
@@ -36,8 +36,13 @@
     }
 
     @JvmOverloads
-    fun create(name: String, maxPoolSize: Int, flexSize: Int = 10): LogBuffer {
-        val buffer = LogBuffer(name, poolLimit(maxPoolSize), flexSize, logcatEchoTracker)
+    fun create(
+        name: String,
+        maxPoolSize: Int,
+        flexSize: Int = 10,
+        systrace: Boolean = true
+    ): LogBuffer {
+        val buffer = LogBuffer(name, poolLimit(maxPoolSize), flexSize, logcatEchoTracker, systrace)
         dumpManager.registerBuffer(name, buffer)
         return buffer
     }
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
index d3bd0a5..1f953d7 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
@@ -49,7 +49,8 @@
     @SysUISingleton
     @NotificationLog
     public static LogBuffer provideNotificationsLogBuffer(LogBufferFactory factory) {
-        return factory.create("NotifLog", 1000);
+        return factory.create("NotifLog", 1000 /* maxPoolSize */,
+                10 /* flexSize */, false /* systrace */);
     }
 
     /** Provides a logging buffer for all logs related to the data layer of notifications. */
@@ -65,7 +66,8 @@
     @SysUISingleton
     @NotificationSectionLog
     public static LogBuffer provideNotificationSectionLogBuffer(LogBufferFactory factory) {
-        return factory.create("NotifSectionLog", 1000);
+        return factory.create("NotifSectionLog", 1000 /* maxPoolSize */,
+                10 /* flexSize */, false /* systrace */);
     }
 
     /** Provides a logging buffer for all logs related to the data layer of notifications. */
@@ -81,7 +83,8 @@
     @SysUISingleton
     @QSLog
     public static LogBuffer provideQuickSettingsLogBuffer(LogBufferFactory factory) {
-        return factory.create("QSLog", 500);
+        return factory.create("QSLog", 500 /* maxPoolSize */,
+                10 /* flexSize */, false /* systrace */);
     }
 
     /** Provides a logging buffer for {@link com.android.systemui.broadcast.BroadcastDispatcher} */
@@ -89,7 +92,8 @@
     @SysUISingleton
     @BroadcastDispatcherLog
     public static LogBuffer provideBroadcastDispatcherLogBuffer(LogBufferFactory factory) {
-        return factory.create("BroadcastDispatcherLog", 500);
+        return factory.create("BroadcastDispatcherLog", 500 /* maxPoolSize */,
+                10 /* flexSize */, false /* systrace */);
     }
 
     /** Provides a logging buffer for all logs related to Toasts shown by SystemUI. */
@@ -127,7 +131,8 @@
     @SysUISingleton
     @QSFragmentDisableLog
     public static LogBuffer provideQSFragmentDisableLogBuffer(LogBufferFactory factory) {
-        return factory.create("QSFragmentDisableFlagsLog", 10);
+        return factory.create("QSFragmentDisableFlagsLog", 10 /* maxPoolSize */,
+                10 /* flexSize */, false /* systrace */);
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
index e921ad29c..ce3b443 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
@@ -18,6 +18,7 @@
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.dump.DumpManager
+import com.android.systemui.media.MediaControlPanel.SMARTSPACE_CARD_DISMISS_EVENT
 import com.android.systemui.plugins.ActivityStarter
 import com.android.systemui.plugins.FalsingManager
 import com.android.systemui.qs.PageIndicator
@@ -56,7 +57,8 @@
     configurationController: ConfigurationController,
     falsingCollector: FalsingCollector,
     falsingManager: FalsingManager,
-    dumpManager: DumpManager
+    dumpManager: DumpManager,
+    private val mediaFlags: MediaFlags
 ) : Dumpable {
     /**
      * The current width of the carousel
@@ -382,7 +384,7 @@
     private fun reorderAllPlayers(previousVisiblePlayerKey: MediaPlayerData.MediaSortKey?) {
         mediaContent.removeAllViews()
         for (mediaPlayer in MediaPlayerData.players()) {
-            mediaPlayer.playerViewHolder?.let {
+            mediaPlayer.mediaViewHolder?.let {
                 mediaContent.addView(it.player)
             } ?: mediaPlayer.recommendationViewHolder?.let {
                 mediaContent.addView(it.recommendations)
@@ -416,12 +418,19 @@
                 .elementAtOrNull(mediaCarouselScrollHandler.visibleMediaIndex)
         if (existingPlayer == null) {
             var newPlayer = mediaControlPanelFactory.get()
-            newPlayer.attachPlayer(
-                    PlayerViewHolder.create(LayoutInflater.from(context), mediaContent))
+            if (mediaFlags.areMediaSessionActionsEnabled()) {
+                newPlayer.attachPlayer(
+                        PlayerSessionViewHolder.create(LayoutInflater.from(context), mediaContent),
+                        MediaViewController.TYPE.PLAYER_SESSION)
+            } else {
+                newPlayer.attachPlayer(
+                        PlayerViewHolder.create(LayoutInflater.from(context), mediaContent),
+                        MediaViewController.TYPE.PLAYER)
+            }
             newPlayer.mediaViewController.sizeChangedListener = this::updateCarouselDimensions
             val lp = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                     ViewGroup.LayoutParams.WRAP_CONTENT)
-            newPlayer.playerViewHolder?.player?.setLayoutParams(lp)
+            newPlayer.mediaViewHolder?.player?.setLayoutParams(lp)
             newPlayer.bindPlayer(dataCopy, key)
             newPlayer.setListening(currentlyExpanded)
             MediaPlayerData.addMediaPlayer(key, dataCopy, newPlayer, systemClock)
@@ -493,7 +502,7 @@
         val removed = MediaPlayerData.removeMediaPlayer(key)
         removed?.apply {
             mediaCarouselScrollHandler.onPrePlayerRemoved(removed)
-            mediaContent.removeView(removed.playerViewHolder?.player)
+            mediaContent.removeView(removed.mediaViewHolder?.player)
             mediaContent.removeView(removed.recommendationViewHolder?.recommendations)
             removed.onDestroy()
             mediaCarouselScrollHandler.onPlayersChanged()
@@ -836,7 +845,7 @@
         MediaPlayerData.players().forEachIndexed {
             index, it ->
             if (it.mIsImpressed) {
-                logSmartspaceCardReported(761, // SMARTSPACE_CARD_DISMISS
+                logSmartspaceCardReported(SMARTSPACE_CARD_DISMISS_EVENT,
                         it.mInstanceId,
                         it.mUid,
                         it.recommendationViewHolder != null,
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt
index cbcec95..5dc4bcf 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt
@@ -528,7 +528,7 @@
      * where it was and update our scroll position.
      */
     fun onPrePlayerRemoved(removed: MediaControlPanel) {
-        val removedIndex = mediaContent.indexOfChild(removed.playerViewHolder?.player)
+        val removedIndex = mediaContent.indexOfChild(removed.mediaViewHolder?.player)
         // If the removed index is less than the visibleMediaIndex, then we need to decrement it.
         // RTL has no effect on this, because indices are always relative (start-to-end).
         // Update the index 'manually' since we won't always get a call to onMediaScrollingChanged
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
index 63555bb..3c23722 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
@@ -57,12 +57,10 @@
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.shared.system.SysUiStatsLog;
-import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
 import com.android.systemui.util.animation.TransitionLayout;
 import com.android.systemui.util.time.SystemClock;
 
 import java.net.URISyntaxException;
-import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.Executor;
 
@@ -87,6 +85,10 @@
     private static final String KEY_SMARTSPACE_ARTIST_NAME = "artist_name";
     private static final String KEY_SMARTSPACE_OPEN_IN_FOREGROUND = "KEY_OPEN_IN_FOREGROUND";
 
+    // Event types logged by smartspace
+    private static final int SMARTSPACE_CARD_CLICK_EVENT = 760;
+    protected static final int SMARTSPACE_CARD_DISMISS_EVENT = 761;
+
     private static final Intent SETTINGS_INTENT = new Intent(ACTION_MEDIA_CONTROLS_SETTINGS);
 
     // Button IDs for QS controls
@@ -104,13 +106,12 @@
     private final ActivityStarter mActivityStarter;
 
     private Context mContext;
-    private PlayerViewHolder mPlayerViewHolder;
+    private MediaViewHolder mMediaViewHolder;
     private RecommendationViewHolder mRecommendationViewHolder;
     private String mKey;
     private MediaViewController mMediaViewController;
     private MediaSession.Token mToken;
     private MediaController mController;
-    private KeyguardDismissUtil mKeyguardDismissUtil;
     private Lazy<MediaDataManager> mMediaDataManagerLazy;
     private int mBackgroundColor;
     private int mDevicePadding;
@@ -139,8 +140,8 @@
     public MediaControlPanel(Context context, @Background Executor backgroundExecutor,
             ActivityStarter activityStarter, MediaViewController mediaViewController,
             SeekBarViewModel seekBarViewModel, Lazy<MediaDataManager> lazyMediaDataManager,
-            KeyguardDismissUtil keyguardDismissUtil, MediaOutputDialogFactory
-            mediaOutputDialogFactory, MediaCarouselController mediaCarouselController,
+            MediaOutputDialogFactory mediaOutputDialogFactory,
+            MediaCarouselController mediaCarouselController,
             FalsingManager falsingManager, MediaFlags mediaFlags, SystemClock systemClock) {
         mContext = context;
         mBackgroundExecutor = backgroundExecutor;
@@ -148,7 +149,6 @@
         mSeekBarViewModel = seekBarViewModel;
         mMediaViewController = mediaViewController;
         mMediaDataManagerLazy = lazyMediaDataManager;
-        mKeyguardDismissUtil = keyguardDismissUtil;
         mMediaOutputDialogFactory = mediaOutputDialogFactory;
         mMediaCarouselController = mediaCarouselController;
         mFalsingManager = falsingManager;
@@ -157,8 +157,7 @@
         loadDimens();
 
         mSeekBarViewModel.setLogSmartspaceClick(() -> {
-            logSmartspaceCardReported(
-                    760, // SMARTSPACE_CARD_CLICK
+            logSmartspaceCardReported(SMARTSPACE_CARD_CLICK_EVENT,
                     /* isRecommendationCard */ false);
             return Unit.INSTANCE;
         });
@@ -179,13 +178,13 @@
     }
 
     /**
-     * Get the player view holder used to display media controls.
+     * Get the view holder used to display media controls.
      *
-     * @return the player view holder
+     * @return the media view holder
      */
     @Nullable
-    public PlayerViewHolder getPlayerViewHolder() {
-        return mPlayerViewHolder;
+    public MediaViewHolder getMediaViewHolder() {
+        return mMediaViewHolder;
     }
 
     /**
@@ -229,16 +228,17 @@
     }
 
     /** Attaches the player to the player view holder. */
-    public void attachPlayer(PlayerViewHolder vh) {
-        mPlayerViewHolder = vh;
+    public void attachPlayer(MediaViewHolder vh, MediaViewController.TYPE playerType) {
+        mMediaViewHolder = vh;
         TransitionLayout player = vh.getPlayer();
 
-        mSeekBarObserver = new SeekBarObserver(vh);
+        boolean useSessionLayout = playerType == MediaViewController.TYPE.PLAYER_SESSION;
+        mSeekBarObserver = new SeekBarObserver(vh, useSessionLayout);
         mSeekBarViewModel.getProgress().observeForever(mSeekBarObserver);
         mSeekBarViewModel.attachTouchHandlers(vh.getSeekBar());
-        mMediaViewController.attach(player, MediaViewController.TYPE.PLAYER);
+        mMediaViewController.attach(player, playerType);
 
-        mPlayerViewHolder.getPlayer().setOnLongClickListener(v -> {
+        vh.getPlayer().setOnLongClickListener(v -> {
             if (!mMediaViewController.isGutsVisible()) {
                 openGuts();
                 return true;
@@ -247,12 +247,12 @@
                 return true;
             }
         });
-        mPlayerViewHolder.getCancel().setOnClickListener(v -> {
+        vh.getCancel().setOnClickListener(v -> {
             if (!mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
                 closeGuts();
             }
         });
-        mPlayerViewHolder.getSettings().setOnClickListener(v -> {
+        vh.getSettings().setOnClickListener(v -> {
             if (!mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
                 mActivityStarter.startActivity(SETTINGS_INTENT, true /* dismissShade */);
             }
@@ -289,9 +289,19 @@
 
     /** Bind this player view based on the data given. */
     public void bindPlayer(@NonNull MediaData data, String key) {
-        if (mPlayerViewHolder == null) {
+        if (mMediaViewHolder == null) {
             return;
         }
+        bindPlayerCommon(data, key);
+        if (mMediaViewHolder instanceof PlayerViewHolder) {
+            bindNotificationPlayer(data, key);
+        } else if (mMediaViewHolder instanceof PlayerSessionViewHolder) {
+            bindSessionPlayer(data, key);
+        }
+    }
+
+    /** Bind elements common to both layouts */
+    private void bindPlayerCommon(@NonNull MediaData data, String key) {
         mKey = key;
         MediaSession.Token token = data.getToken();
         PackageManager packageManager = mContext.getPackageManager();
@@ -316,99 +326,63 @@
             mController = null;
         }
 
-        ConstraintSet expandedSet = mMediaViewController.getExpandedLayout();
-        ConstraintSet collapsedSet = mMediaViewController.getCollapsedLayout();
-
         // Click action
         PendingIntent clickIntent = data.getClickIntent();
         if (clickIntent != null) {
-            mPlayerViewHolder.getPlayer().setOnClickListener(v -> {
+            mMediaViewHolder.getPlayer().setOnClickListener(v -> {
                 if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) return;
                 if (mMediaViewController.isGutsVisible()) return;
 
-                logSmartspaceCardReported(760, // SMARTSPACE_CARD_CLICK
+                logSmartspaceCardReported(SMARTSPACE_CARD_CLICK_EVENT,
                         /* isRecommendationCard */ false);
                 mActivityStarter.postStartActivityDismissingKeyguard(clickIntent,
-                        buildLaunchAnimatorController(mPlayerViewHolder.getPlayer()));
+                        buildLaunchAnimatorController(mMediaViewHolder.getPlayer()));
             });
         }
 
         // Accessibility label
-        mPlayerViewHolder.getPlayer().setContentDescription(
+        mMediaViewHolder.getPlayer().setContentDescription(
                 mContext.getString(
                         R.string.controls_media_playing_item_description,
                         data.getSong(), data.getArtist(), data.getApp()));
 
-        ImageView albumView = mPlayerViewHolder.getAlbumView();
-        boolean hasArtwork = data.getArtwork() != null;
-        if (hasArtwork) {
-            Drawable artwork = scaleDrawable(data.getArtwork());
-            albumView.setPadding(0, 0, 0, 0);
-            albumView.setImageDrawable(artwork);
-        } else {
-            Drawable deviceIcon;
-            if (data.getDevice() != null && data.getDevice().getIcon() != null) {
-                deviceIcon = data.getDevice().getIcon().getConstantState().newDrawable().mutate();
-            } else {
-                deviceIcon = getContext().getDrawable(R.drawable.ic_headphone);
-            }
-            deviceIcon.setTintList(ColorStateList.valueOf(mBackgroundColor));
-            albumView.setPadding(mDevicePadding, mDevicePadding, mDevicePadding, mDevicePadding);
-            albumView.setImageDrawable(deviceIcon);
-        }
-
-        // App icon
-        ImageView appIconView = mPlayerViewHolder.getAppIcon();
-        appIconView.clearColorFilter();
-        if (data.getAppIcon() != null && !data.getResumption()) {
-            appIconView.setImageIcon(data.getAppIcon());
-            int color = mContext.getColor(android.R.color.system_accent2_900);
-            appIconView.setColorFilter(color);
-        } else {
-            appIconView.setColorFilter(getGrayscaleFilter());
-            try {
-                Drawable icon = mContext.getPackageManager().getApplicationIcon(
-                        data.getPackageName());
-                appIconView.setImageDrawable(icon);
-            } catch (PackageManager.NameNotFoundException e) {
-                Log.w(TAG, "Cannot find icon for package " + data.getPackageName(), e);
-                appIconView.setImageResource(R.drawable.ic_music_note);
-            }
-        }
-
         // Song name
-        TextView titleText = mPlayerViewHolder.getTitleText();
+        TextView titleText = mMediaViewHolder.getTitleText();
         titleText.setText(data.getSong());
 
         // Artist name
-        TextView artistText = mPlayerViewHolder.getArtistText();
+        TextView artistText = mMediaViewHolder.getArtistText();
         artistText.setText(data.getArtist());
 
-        // Transfer chip
-        ViewGroup seamlessView = mPlayerViewHolder.getSeamless();
+        // Seek Bar
+        final MediaController controller = getController();
+        mBackgroundExecutor.execute(() -> mSeekBarViewModel.updateController(controller));
+
+        // Guts label
+        boolean isDismissible = data.isClearable();
+        mMediaViewHolder.getLongPressText().setText(isDismissible
+                ? R.string.controls_media_close_session
+                : R.string.controls_media_active_session);
+
+        // Output switcher chip
+        ViewGroup seamlessView = mMediaViewHolder.getSeamless();
         seamlessView.setVisibility(View.VISIBLE);
-        setVisibleAndAlpha(collapsedSet, R.id.media_seamless, true /*visible */);
-        setVisibleAndAlpha(expandedSet, R.id.media_seamless, true /*visible */);
         seamlessView.setOnClickListener(
                 v -> {
                     if (!mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
                         mMediaOutputDialogFactory.create(data.getPackageName(), true,
-                                mPlayerViewHolder.getSeamlessButton());
+                                mMediaViewHolder.getSeamlessButton());
                     }
                 });
-
-        ImageView iconView = mPlayerViewHolder.getSeamlessIcon();
-        TextView deviceName = mPlayerViewHolder.getSeamlessText();
-
+        ImageView iconView = mMediaViewHolder.getSeamlessIcon();
+        TextView deviceName = mMediaViewHolder.getSeamlessText();
         final MediaDeviceData device = data.getDevice();
-        final int seamlessId = mPlayerViewHolder.getSeamless().getId();
         // 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);
-        mPlayerViewHolder.getSeamless().setEnabled(!seamlessDisabled);
+        mMediaViewHolder.getSeamlessButton().setAlpha(seamlessAlpha);
+        seamlessView.setEnabled(!seamlessDisabled);
         String deviceString = null;
         if (device != null && device.getEnabled()) {
             Drawable icon = device.getIcon();
@@ -429,32 +403,88 @@
         deviceName.setText(deviceString);
         seamlessView.setContentDescription(deviceString);
 
+        // Dismiss
+        mMediaViewHolder.getDismissLabel().setAlpha(isDismissible ? 1 : DISABLED_ALPHA);
+        mMediaViewHolder.getDismiss().setEnabled(isDismissible);
+        mMediaViewHolder.getDismiss().setOnClickListener(v -> {
+            if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) return;
+
+            logSmartspaceCardReported(SMARTSPACE_CARD_DISMISS_EVENT,
+                    /* isRecommendationCard */ false);
+
+            if (mKey != null) {
+                closeGuts();
+                if (!mMediaDataManagerLazy.get().dismissMediaData(mKey,
+                        MediaViewController.GUTS_ANIMATION_DURATION + 100)) {
+                    Log.w(TAG, "Manager failed to dismiss media " + mKey);
+                    // Remove directly from carousel so user isn't stuck with defunct controls
+                    mMediaCarouselController.removePlayer(key, false, false);
+                }
+            } else {
+                Log.w(TAG, "Dismiss media with null notification. Token uid="
+                        + data.getToken().getUid());
+            }
+        });
+
+        // TODO: We don't need to refresh this state constantly, only if the state actually changed
+        // to something which might impact the measurement
+        mMediaViewController.refreshState();
+    }
+
+    /** Bind elements specific to PlayerViewHolder */
+    private void bindNotificationPlayer(@NonNull MediaData data, String key) {
+        ConstraintSet expandedSet = mMediaViewController.getExpandedLayout();
+        ConstraintSet collapsedSet = mMediaViewController.getCollapsedLayout();
+
+        // Album art
+        PlayerViewHolder playerHolder = (PlayerViewHolder) mMediaViewHolder;
+        ImageView albumView = playerHolder.getAlbumView();
+        boolean hasArtwork = data.getArtwork() != null;
+        if (hasArtwork) {
+            Drawable artwork = scaleDrawable(data.getArtwork());
+            albumView.setPadding(0, 0, 0, 0);
+            albumView.setImageDrawable(artwork);
+        } else {
+            Drawable deviceIcon;
+            if (data.getDevice() != null && data.getDevice().getIcon() != null) {
+                deviceIcon = data.getDevice().getIcon().getConstantState().newDrawable().mutate();
+            } else {
+                deviceIcon = getContext().getDrawable(R.drawable.ic_headphone);
+            }
+            deviceIcon.setTintList(ColorStateList.valueOf(mBackgroundColor));
+            albumView.setPadding(mDevicePadding, mDevicePadding, mDevicePadding, mDevicePadding);
+            albumView.setImageDrawable(deviceIcon);
+        }
+
+        // App icon - use notification icon
+        ImageView appIconView = mMediaViewHolder.getAppIcon();
+        appIconView.clearColorFilter();
+        if (data.getAppIcon() != null && !data.getResumption()) {
+            appIconView.setImageIcon(data.getAppIcon());
+            int color = mContext.getColor(android.R.color.system_accent2_900);
+            appIconView.setColorFilter(color);
+        } else {
+            // Resume players use launcher icon
+            appIconView.setColorFilter(getGrayscaleFilter());
+            try {
+                Drawable icon = mContext.getPackageManager().getApplicationIcon(
+                        data.getPackageName());
+                appIconView.setImageDrawable(icon);
+            } catch (PackageManager.NameNotFoundException e) {
+                Log.w(TAG, "Cannot find icon for package " + data.getPackageName(), e);
+                appIconView.setImageResource(R.drawable.ic_music_note);
+            }
+        }
+
         // Media action buttons
         List<MediaAction> actionIcons = data.getActions();
         List<Integer> actionsWhenCollapsed = data.getActionsToShowInCompact();
 
-        if (mMediaFlags.areMediaSessionActionsEnabled() && data.getSemanticActions() != null) {
-            // Use PlaybackState actions instead
-            MediaButton semanticActions = data.getSemanticActions();
-
-            actionIcons = new ArrayList<MediaAction>();
-            actionIcons.add(semanticActions.getStartCustom());
-            actionIcons.add(semanticActions.getPrevOrCustom());
-            actionIcons.add(semanticActions.getPlayOrPause());
-            actionIcons.add(semanticActions.getNextOrCustom());
-            actionIcons.add(semanticActions.getEndCustom());
-
-            actionsWhenCollapsed = new ArrayList<Integer>();
-            actionsWhenCollapsed.add(1);
-            actionsWhenCollapsed.add(2);
-            actionsWhenCollapsed.add(3);
-        }
-
         int i = 0;
         for (; i < actionIcons.size() && i < ACTION_IDS.length; i++) {
             int actionId = ACTION_IDS[i];
             boolean visibleInCompat = actionsWhenCollapsed.contains(i);
-            final ImageButton button = mPlayerViewHolder.getAction(actionId);
+            final ImageButton button = mMediaViewHolder.getAction(actionId);
             MediaAction mediaAction = actionIcons.get(i);
             if (mediaAction != null) {
                 button.setImageIcon(mediaAction.getIcon());
@@ -467,7 +497,7 @@
                     button.setEnabled(true);
                     button.setOnClickListener(v -> {
                         if (!mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
-                            logSmartspaceCardReported(760, // SMARTSPACE_CARD_CLICK
+                            logSmartspaceCardReported(SMARTSPACE_CARD_CLICK_EVENT,
                                     /* isRecommendationCard */ false);
                             action.run();
                         }
@@ -495,43 +525,71 @@
         if (actionIcons.size() == 0) {
             expandedSet.setVisibility(ACTION_IDS[0], ConstraintSet.INVISIBLE);
         }
+    }
 
-        // Seek Bar
-        final MediaController controller = getController();
-        mBackgroundExecutor.execute(() -> mSeekBarViewModel.updateController(controller));
-
-        // Guts label
-        boolean isDismissible = data.isClearable();
-        mPlayerViewHolder.getLongPressText().setText(isDismissible
-                ? R.string.controls_media_close_session
-                : R.string.controls_media_active_session);
-
-        // Dismiss
-        mPlayerViewHolder.getDismissLabel().setAlpha(isDismissible ? 1 : DISABLED_ALPHA);
-        mPlayerViewHolder.getDismiss().setEnabled(isDismissible);
-        mPlayerViewHolder.getDismiss().setOnClickListener(v -> {
-            if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) return;
-
-            logSmartspaceCardReported(761, // SMARTSPACE_CARD_DISMISS
-                    /* isRecommendationCard */ false);
-
-            if (mKey != null) {
-                closeGuts();
-                if (!mMediaDataManagerLazy.get().dismissMediaData(mKey,
-                        MediaViewController.GUTS_ANIMATION_DURATION + 100)) {
-                    Log.w(TAG, "Manager failed to dismiss media " + mKey);
-                    // Remove directly from carousel to let user recover - TODO(b/190799184)
-                    mMediaCarouselController.removePlayer(key, false, false);
-                }
+    /** Bind elements specific to PlayerSessionViewHolder */
+    private void bindSessionPlayer(@NonNull MediaData data, String key) {
+        // App icon - use launcher icon
+        ImageView appIconView = mMediaViewHolder.getAppIcon();
+        appIconView.clearColorFilter();
+        try {
+            Drawable icon = mContext.getPackageManager().getApplicationIcon(
+                    data.getPackageName());
+            appIconView.setImageDrawable(icon);
+        } catch (PackageManager.NameNotFoundException e) {
+            Log.w(TAG, "Cannot find icon for package " + data.getPackageName(), e);
+            // Fall back to notification icon
+            if (data.getAppIcon() != null) {
+                appIconView.setImageIcon(data.getAppIcon());
             } else {
-                Log.w(TAG, "Dismiss media with null notification. Token uid="
-                        + data.getToken().getUid());
+                appIconView.setImageResource(R.drawable.ic_music_note);
             }
-        });
+            int color = mContext.getColor(android.R.color.system_accent2_900);
+            appIconView.setColorFilter(color);
+        }
 
-        // TODO: We don't need to refresh this state constantly, only if the state actually changed
-        // to something which might impact the measurement
-        mMediaViewController.refreshState();
+        // Media action buttons
+        MediaButton semanticActions = data.getSemanticActions();
+        if (semanticActions != null) {
+            PlayerSessionViewHolder sessionHolder = (PlayerSessionViewHolder) mMediaViewHolder;
+            setSemanticButton(sessionHolder.getActionPlayPause(),
+                    semanticActions.getPlayOrPause());
+            setSemanticButton(sessionHolder.getActionNext(),
+                    semanticActions.getNextOrCustom());
+            setSemanticButton(sessionHolder.getActionPrev(),
+                    semanticActions.getPrevOrCustom());
+            setSemanticButton(sessionHolder.getActionStart(),
+                    semanticActions.getStartCustom());
+            setSemanticButton(sessionHolder.getActionEnd(),
+                    semanticActions.getEndCustom());
+        } else {
+            Log.w(TAG, "Using semantic player, but did not get buttons");
+        }
+    }
+
+    private void setSemanticButton(final ImageButton button, MediaAction mediaAction) {
+        if (mediaAction != null) {
+            button.setImageIcon(mediaAction.getIcon());
+            button.setContentDescription(mediaAction.getContentDescription());
+
+            Runnable action = mediaAction.getAction();
+            if (action == null) {
+                button.setEnabled(false);
+            } else {
+                button.setEnabled(true);
+                button.setOnClickListener(v -> {
+                    if (!mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
+                        logSmartspaceCardReported(SMARTSPACE_CARD_CLICK_EVENT,
+                                /* isRecommendationCard */ false);
+                        action.run();
+                    }
+                });
+            }
+        } else {
+            button.setImageIcon(null);
+            button.setContentDescription(null);
+            button.setEnabled(false);
+        }
     }
 
     @Nullable
@@ -696,7 +754,7 @@
         mRecommendationViewHolder.getDismiss().setOnClickListener(v -> {
             if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) return;
 
-            logSmartspaceCardReported(761, // SMARTSPACE_CARD_DISMISS
+            logSmartspaceCardReported(SMARTSPACE_CARD_DISMISS_EVENT,
                     /* isRecommendationCard */ true);
             closeGuts();
             mMediaDataManagerLazy.get().dismissSmartspaceRecommendation(
@@ -729,8 +787,8 @@
      * @param immediate {@code true} if it should be closed without animation
      */
     public void closeGuts(boolean immediate) {
-        if (mPlayerViewHolder != null) {
-            mPlayerViewHolder.marquee(false, mMediaViewController.GUTS_ANIMATION_DURATION);
+        if (mMediaViewHolder != null) {
+            mMediaViewHolder.marquee(false, mMediaViewController.GUTS_ANIMATION_DURATION);
         } else if (mRecommendationViewHolder != null) {
             mRecommendationViewHolder.marquee(false, mMediaViewController.GUTS_ANIMATION_DURATION);
         }
@@ -747,9 +805,9 @@
 
         boolean wasTruncated = false;
         Layout l = null;
-        if (mPlayerViewHolder != null) {
-            mPlayerViewHolder.marquee(true, mMediaViewController.GUTS_ANIMATION_DURATION);
-            l = mPlayerViewHolder.getSettingsText().getLayout();
+        if (mMediaViewHolder != null) {
+            mMediaViewHolder.marquee(true, mMediaViewController.GUTS_ANIMATION_DURATION);
+            l = mMediaViewHolder.getSettingsText().getLayout();
         } else if (mRecommendationViewHolder != null) {
             mRecommendationViewHolder.marquee(true, mMediaViewController.GUTS_ANIMATION_DURATION);
             l = mRecommendationViewHolder.getSettingsText().getLayout();
@@ -853,7 +911,7 @@
         view.setOnClickListener(v -> {
             if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) return;
 
-            logSmartspaceCardReported(760, // SMARTSPACE_CARD_CLICK
+            logSmartspaceCardReported(SMARTSPACE_CARD_CLICK_EVENT,
                     /* isRecommendationCard */ true,
                     interactedSubcardRank,
                     getSmartspaceSubCardCardinality());
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt
index 3681a2a..791a312 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt
@@ -37,9 +37,12 @@
     private val mediaHostStatesManager: MediaHostStatesManager
 ) {
 
-    /** Indicating the media view controller is for a player or recommendation. */
+    /**
+     * Indicating that the media view controller is for a notification-based player,
+     * session-based player, or recommendation
+     */
     enum class TYPE {
-        PLAYER, RECOMMENDATION
+        PLAYER, PLAYER_SESSION, RECOMMENDATION
     }
 
     companion object {
@@ -257,31 +260,29 @@
      * [TransitionViewState].
      */
     private fun setGutsViewState(viewState: TransitionViewState) {
-        if (type == TYPE.PLAYER) {
-            PlayerViewHolder.controlsIds.forEach { id ->
-                viewState.widgetStates.get(id)?.let { state ->
-                    // Make sure to use the unmodified state if guts are not visible.
-                    state.alpha = if (isGutsVisible) 0f else state.alpha
-                    state.gone = if (isGutsVisible) true else state.gone
-                }
-            }
-            PlayerViewHolder.gutsIds.forEach { id ->
-                viewState.widgetStates.get(id)?.alpha = if (isGutsVisible) 1f else 0f
-                viewState.widgetStates.get(id)?.gone = !isGutsVisible
-            }
-        } else {
-            RecommendationViewHolder.controlsIds.forEach { id ->
-                viewState.widgetStates.get(id)?.let { state ->
-                    // Make sure to use the unmodified state if guts are not visible.
-                    state.alpha = if (isGutsVisible) 0f else state.alpha
-                    state.gone = if (isGutsVisible) true else state.gone
-                }
-            }
-            RecommendationViewHolder.gutsIds.forEach { id ->
-                viewState.widgetStates.get(id)?.alpha = if (isGutsVisible) 1f else 0f
-                viewState.widgetStates.get(id)?.gone = !isGutsVisible
+        val controlsIds = when (type) {
+            TYPE.PLAYER -> PlayerViewHolder.controlsIds
+            TYPE.PLAYER_SESSION -> PlayerSessionViewHolder.controlsIds
+            TYPE.RECOMMENDATION -> RecommendationViewHolder.controlsIds
+        }
+        val gutsIds = when (type) {
+            TYPE.PLAYER -> PlayerViewHolder.gutsIds
+            TYPE.PLAYER_SESSION -> PlayerSessionViewHolder.gutsIds
+            TYPE.RECOMMENDATION -> RecommendationViewHolder.gutsIds
+        }
+
+        controlsIds.forEach { id ->
+            viewState.widgetStates.get(id)?.let { state ->
+                // Make sure to use the unmodified state if guts are not visible.
+                state.alpha = if (isGutsVisible) 0f else state.alpha
+                state.gone = if (isGutsVisible) true else state.gone
             }
         }
+        gutsIds.forEach { id ->
+            viewState.widgetStates.get(id)?.alpha = if (isGutsVisible) 1f else 0f
+            viewState.widgetStates.get(id)?.gone = !isGutsVisible
+        }
+
         if (shouldHideGutsSettings) {
             viewState.widgetStates.get(R.id.settings)?.gone = true
         }
@@ -470,12 +471,19 @@
 
     private fun updateMediaViewControllerType(type: TYPE) {
         this.type = type
-        if (type == TYPE.PLAYER) {
-            collapsedLayout.load(context, R.xml.media_collapsed)
-            expandedLayout.load(context, R.xml.media_expanded)
-        } else {
-            collapsedLayout.load(context, R.xml.media_recommendation_collapsed)
-            expandedLayout.load(context, R.xml.media_recommendation_expanded)
+        when (type) {
+            TYPE.PLAYER -> {
+                collapsedLayout.load(context, R.xml.media_collapsed)
+                expandedLayout.load(context, R.xml.media_expanded)
+            }
+            TYPE.PLAYER_SESSION -> {
+                collapsedLayout.clone(context, R.layout.media_session_view)
+                expandedLayout.clone(context, R.layout.media_session_view)
+            }
+            TYPE.RECOMMENDATION -> {
+                collapsedLayout.load(context, R.xml.media_recommendation_collapsed)
+                expandedLayout.load(context, R.xml.media_recommendation_expanded)
+            }
         }
         refreshState()
     }
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaViewHolder.kt b/packages/SystemUI/src/com/android/systemui/media/MediaViewHolder.kt
new file mode 100644
index 0000000..c333b50
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaViewHolder.kt
@@ -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.systemui.media
+
+import android.util.Log
+import android.view.View
+import android.view.ViewGroup
+import android.widget.ImageButton
+import android.widget.ImageView
+import android.widget.SeekBar
+import android.widget.TextView
+import com.android.systemui.R
+import com.android.systemui.util.animation.TransitionLayout
+
+private const val TAG = "MediaViewHolder"
+
+/**
+ * Parent class for different media player views
+ */
+abstract class MediaViewHolder constructor(itemView: View) {
+    val player = itemView as TransitionLayout
+
+    // Player information
+    val appIcon = itemView.requireViewById<ImageView>(R.id.icon)
+    val titleText = itemView.requireViewById<TextView>(R.id.header_title)
+    val artistText = itemView.requireViewById<TextView>(R.id.header_artist)
+
+    // Output switcher
+    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 seamlessButton = itemView.requireViewById<View>(R.id.media_seamless_button)
+
+    // Seekbar views
+    val seekBar = itemView.requireViewById<SeekBar>(R.id.media_progress_bar)
+    open val elapsedTimeView: TextView? = null
+    open val totalTimeView: TextView? = null
+
+    // Settings screen
+    val longPressText = itemView.requireViewById<TextView>(R.id.remove_text)
+    val cancel = itemView.requireViewById<View>(R.id.cancel)
+    val dismiss = itemView.requireViewById<ViewGroup>(R.id.dismiss)
+    val dismissLabel = dismiss.getChildAt(0)
+    val settings = itemView.requireViewById<View>(R.id.settings)
+    val settingsText = itemView.requireViewById<TextView>(R.id.settings_text)
+
+    init {
+        (player.background as IlluminationDrawable).let {
+            it.registerLightSource(seamless)
+            it.registerLightSource(cancel)
+            it.registerLightSource(dismiss)
+            it.registerLightSource(settings)
+        }
+    }
+
+    abstract fun getAction(id: Int): ImageButton
+
+    fun marquee(start: Boolean, delay: Long) {
+        val longPressTextHandler = longPressText.getHandler()
+        if (longPressTextHandler == null) {
+            Log.d(TAG, "marquee while longPressText.getHandler() is null", Exception())
+            return
+        }
+        longPressTextHandler.postDelayed({ longPressText.setSelected(start) }, delay)
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/media/PlayerSessionViewHolder.kt b/packages/SystemUI/src/com/android/systemui/media/PlayerSessionViewHolder.kt
new file mode 100644
index 0000000..87d2cff
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/PlayerSessionViewHolder.kt
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.media
+
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.ImageButton
+import com.android.systemui.R
+
+/**
+ * ViewHolder for a media player with MediaSession-based controls
+ */
+class PlayerSessionViewHolder private constructor(itemView: View) : MediaViewHolder(itemView) {
+
+    // Action Buttons
+    val actionPlayPause = itemView.requireViewById<ImageButton>(R.id.actionPlayPause)
+    val actionNext = itemView.requireViewById<ImageButton>(R.id.actionNext)
+    val actionPrev = itemView.requireViewById<ImageButton>(R.id.actionPrev)
+    val actionStart = itemView.requireViewById<ImageButton>(R.id.actionStart)
+    val actionEnd = itemView.requireViewById<ImageButton>(R.id.actionEnd)
+
+    init {
+        (player.background as IlluminationDrawable).let {
+            it.registerLightSource(actionPlayPause)
+            it.registerLightSource(actionNext)
+            it.registerLightSource(actionPrev)
+            it.registerLightSource(actionStart)
+            it.registerLightSource(actionEnd)
+        }
+    }
+
+    override fun getAction(id: Int): ImageButton {
+        return when (id) {
+            R.id.actionPlayPause -> actionPlayPause
+            R.id.actionNext -> actionNext
+            R.id.actionPrev -> actionPrev
+            R.id.actionStart -> actionStart
+            R.id.actionEnd -> actionEnd
+            else -> {
+                throw IllegalArgumentException()
+            }
+        }
+    }
+
+    companion object {
+        /**
+         * Creates a PlayerSessionViewHolder.
+         *
+         * @param inflater LayoutInflater to use to inflate the layout.
+         * @param parent Parent of inflated view.
+         */
+        @JvmStatic fun create(
+            inflater: LayoutInflater,
+            parent: ViewGroup
+        ): PlayerSessionViewHolder {
+            val mediaView = inflater.inflate(R.layout.media_session_view, parent, false)
+            mediaView.setLayerType(View.LAYER_TYPE_HARDWARE, null)
+            // Because this media view (a TransitionLayout) is used to measure and layout the views
+            // in various states before being attached to its parent, we can't depend on the default
+            // LAYOUT_DIRECTION_INHERIT to correctly resolve the ltr direction.
+            mediaView.layoutDirection = View.LAYOUT_DIRECTION_LOCALE
+            return PlayerSessionViewHolder(mediaView).apply {
+                // Media playback is in the direction of tape, not time, so it stays LTR
+                seekBar.layoutDirection = View.LAYOUT_DIRECTION_LTR
+            }
+        }
+
+        val controlsIds = setOf(
+                R.id.icon,
+                R.id.app_name,
+                R.id.header_title,
+                R.id.header_artist,
+                R.id.media_seamless,
+                R.id.media_progress_bar,
+                R.id.actionPlayPause,
+                R.id.actionNext,
+                R.id.actionPrev,
+                R.id.actionStart,
+                R.id.actionEnd,
+                R.id.icon
+        )
+        val gutsIds = setOf(
+                R.id.remove_text,
+                R.id.cancel,
+                R.id.dismiss,
+                R.id.settings
+        )
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt b/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt
index 1322ade..a1faa40 100644
--- a/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt
@@ -16,43 +16,26 @@
 
 package com.android.systemui.media
 
-import android.util.Log
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
 import android.widget.ImageButton
 import android.widget.ImageView
-import android.widget.SeekBar
 import android.widget.TextView
 import com.android.systemui.R
-import com.android.systemui.util.animation.TransitionLayout
-
-private const val TAG = "PlayerViewHolder"
 
 /**
  * ViewHolder for a media player.
  */
-class PlayerViewHolder private constructor(itemView: View) {
-
-    val player = itemView as TransitionLayout
+class PlayerViewHolder private constructor(itemView: View) : MediaViewHolder(itemView) {
 
     // Player information
-    val appIcon = itemView.requireViewById<ImageView>(R.id.icon)
     val albumView = itemView.requireViewById<ImageView>(R.id.album_art)
-    val titleText = itemView.requireViewById<TextView>(R.id.header_title)
-    val artistText = itemView.requireViewById<TextView>(R.id.header_artist)
-
-    // Output switcher
-    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 seamlessButton = itemView.requireViewById<View>(R.id.media_seamless_button)
 
     // Seek bar
-    val seekBar = itemView.requireViewById<SeekBar>(R.id.media_progress_bar)
     val progressTimes = itemView.requireViewById<ViewGroup>(R.id.notification_media_progress_time)
-    val elapsedTimeView = itemView.requireViewById<TextView>(R.id.media_elapsed_time)
-    val totalTimeView = itemView.requireViewById<TextView>(R.id.media_total_time)
+    override val elapsedTimeView = itemView.requireViewById<TextView>(R.id.media_elapsed_time)
+    override val totalTimeView = itemView.requireViewById<TextView>(R.id.media_total_time)
 
     // Action Buttons
     val action0 = itemView.requireViewById<ImageButton>(R.id.action0)
@@ -61,29 +44,17 @@
     val action3 = itemView.requireViewById<ImageButton>(R.id.action3)
     val action4 = itemView.requireViewById<ImageButton>(R.id.action4)
 
-    // Settings screen
-    val longPressText = itemView.requireViewById<TextView>(R.id.remove_text)
-    val cancel = itemView.requireViewById<View>(R.id.cancel)
-    val dismiss = itemView.requireViewById<ViewGroup>(R.id.dismiss)
-    val dismissLabel = dismiss.getChildAt(0)
-    val settings = itemView.requireViewById<View>(R.id.settings)
-    val settingsText = itemView.requireViewById<TextView>(R.id.settings_text)
-
     init {
         (player.background as IlluminationDrawable).let {
-            it.registerLightSource(seamless)
             it.registerLightSource(action0)
             it.registerLightSource(action1)
             it.registerLightSource(action2)
             it.registerLightSource(action3)
             it.registerLightSource(action4)
-            it.registerLightSource(cancel)
-            it.registerLightSource(dismiss)
-            it.registerLightSource(settings)
         }
     }
 
-    fun getAction(id: Int): ImageButton {
+    override fun getAction(id: Int): ImageButton {
         return when (id) {
             R.id.action0 -> action0
             R.id.action1 -> action1
@@ -96,15 +67,6 @@
         }
     }
 
-    fun marquee(start: Boolean, delay: Long) {
-        val longPressTextHandler = longPressText.getHandler()
-        if (longPressTextHandler == null) {
-            Log.d(TAG, "marquee while longPressText.getHandler() is null", Exception())
-            return
-        }
-        longPressTextHandler.postDelayed({ longPressText.setSelected(start) }, delay)
-    }
-
     companion object {
         /**
          * Creates a PlayerViewHolder.
diff --git a/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt b/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt
index 33ef19a..cf997055 100644
--- a/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt
@@ -26,16 +26,29 @@
  *
  * <p>Updates the seek bar views in response to changes to the model.
  */
-class SeekBarObserver(private val holder: PlayerViewHolder) : Observer<SeekBarViewModel.Progress> {
+class SeekBarObserver(
+    private val holder: MediaViewHolder,
+    private val useSessionLayout: Boolean
+) : Observer<SeekBarViewModel.Progress> {
 
     val seekBarEnabledMaxHeight = holder.seekBar.context.resources
         .getDimensionPixelSize(R.dimen.qs_media_enabled_seekbar_height)
     val seekBarDisabledHeight = holder.seekBar.context.resources
         .getDimensionPixelSize(R.dimen.qs_media_disabled_seekbar_height)
-    val seekBarEnabledVerticalPadding = holder.seekBar.context.resources
-            .getDimensionPixelSize(R.dimen.qs_media_enabled_seekbar_vertical_padding)
-    val seekBarDisabledVerticalPadding = holder.seekBar.context.resources
-            .getDimensionPixelSize(R.dimen.qs_media_disabled_seekbar_vertical_padding)
+    val seekBarEnabledVerticalPadding = if (useSessionLayout) {
+        holder.seekBar.context.resources
+                .getDimensionPixelSize(R.dimen.qs_media_session_enabled_seekbar_vertical_padding)
+    } else {
+        holder.seekBar.context.resources
+                .getDimensionPixelSize(R.dimen.qs_media_enabled_seekbar_vertical_padding)
+    }
+    val seekBarDisabledVerticalPadding = if (useSessionLayout) {
+        holder.seekBar.context.resources
+                .getDimensionPixelSize(R.dimen.qs_media_session_disabled_seekbar_vertical_padding)
+    } else {
+        holder.seekBar.context.resources
+                .getDimensionPixelSize(R.dimen.qs_media_disabled_seekbar_vertical_padding)
+    }
 
     /** Updates seek bar views when the data model changes. */
     @UiThread
@@ -48,8 +61,8 @@
             holder.seekBar.setEnabled(false)
             holder.seekBar.getThumb().setAlpha(0)
             holder.seekBar.setProgress(0)
-            holder.elapsedTimeView.setText("")
-            holder.totalTimeView.setText("")
+            holder.elapsedTimeView?.setText("")
+            holder.totalTimeView?.setText("")
             holder.seekBar.contentDescription = ""
             return
         }
@@ -65,13 +78,13 @@
         holder.seekBar.setMax(data.duration)
         val totalTimeString = DateUtils.formatElapsedTime(
             data.duration / DateUtils.SECOND_IN_MILLIS)
-        holder.totalTimeView.setText(totalTimeString)
+        holder.totalTimeView?.setText(totalTimeString)
 
         data.elapsedTime?.let {
             holder.seekBar.setProgress(it)
             val elapsedTimeString = DateUtils.formatElapsedTime(
                 it / DateUtils.SECOND_IN_MILLIS)
-            holder.elapsedTimeView.setText(elapsedTimeString)
+            holder.elapsedTimeView?.setText(elapsedTimeString)
 
             holder.seekBar.contentDescription = holder.seekBar.context.getString(
                 R.string.controls_media_seekbar_description,
diff --git a/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java b/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java
index 1174fa8..558f0e6 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java
@@ -26,9 +26,10 @@
 import com.android.systemui.media.MediaHierarchyManager;
 import com.android.systemui.media.MediaHost;
 import com.android.systemui.media.MediaHostStatesManager;
-import com.android.systemui.media.taptotransfer.MediaTttChipController;
 import com.android.systemui.media.taptotransfer.MediaTttCommandLineHelper;
 import com.android.systemui.media.taptotransfer.MediaTttFlags;
+import com.android.systemui.media.taptotransfer.receiver.MediaTttChipControllerReceiver;
+import com.android.systemui.media.taptotransfer.sender.MediaTttChipControllerSender;
 import com.android.systemui.statusbar.commandline.CommandRegistry;
 import com.android.systemui.util.concurrency.DelayableExecutor;
 
@@ -80,7 +81,7 @@
     /** */
     @Provides
     @SysUISingleton
-    static Optional<MediaTttChipController> providesMediaTttChipController(
+    static Optional<MediaTttChipControllerSender> providesMediaTttChipControllerSender(
             MediaTttFlags mediaTttFlags,
             Context context,
             WindowManager windowManager,
@@ -89,22 +90,42 @@
         if (!mediaTttFlags.isMediaTttEnabled()) {
             return Optional.empty();
         }
-        return Optional.of(new MediaTttChipController(
+        return Optional.of(new MediaTttChipControllerSender(
                 context, windowManager, mainExecutor, backgroundExecutor));
     }
 
     /** */
     @Provides
     @SysUISingleton
+    static Optional<MediaTttChipControllerReceiver> providesMediaTttChipControllerReceiver(
+            MediaTttFlags mediaTttFlags,
+            Context context,
+            WindowManager windowManager) {
+        if (!mediaTttFlags.isMediaTttEnabled()) {
+            return Optional.empty();
+        }
+        return Optional.of(new MediaTttChipControllerReceiver(context, windowManager));
+    }
+
+    /** */
+    @Provides
+    @SysUISingleton
     static Optional<MediaTttCommandLineHelper> providesMediaTttCommandLineHelper(
             MediaTttFlags mediaTttFlags,
             CommandRegistry commandRegistry,
-            MediaTttChipController mediaTttChipController,
+            Context context,
+            MediaTttChipControllerSender mediaTttChipControllerSender,
+            MediaTttChipControllerReceiver mediaTttChipControllerReceiver,
             @Main DelayableExecutor mainExecutor) {
         if (!mediaTttFlags.isMediaTttEnabled()) {
             return Optional.empty();
         }
-        return Optional.of(new MediaTttCommandLineHelper(
-                commandRegistry, mediaTttChipController, mainExecutor));
+        return Optional.of(
+                new MediaTttCommandLineHelper(
+                        commandRegistry,
+                        context,
+                        mediaTttChipControllerSender,
+                        mediaTttChipControllerReceiver,
+                        mainExecutor));
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
index 8b19ccb..e465ae4 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
@@ -66,18 +66,6 @@
         if (position == size && mController.isZeroMode()) {
             viewHolder.onBind(CUSTOMIZED_ITEM_PAIR_NEW, false /* topMargin */,
                     true /* bottomMargin */);
-        } else if (mIncludeDynamicGroup) {
-            if (position == 0) {
-                viewHolder.onBind(CUSTOMIZED_ITEM_DYNAMIC_GROUP, true /* topMargin */,
-                        false /* bottomMargin */);
-            } else {
-                // When group item is added at the first(position == 0), devices will be added from
-                // the second item(position == 1). It means that the index of device list starts
-                // from "position - 1".
-                viewHolder.onBind(((List<MediaDevice>) (mController.getMediaDevices()))
-                                .get(position - 1),
-                        false /* topMargin */, position == size /* bottomMargin */, position);
-            }
         } else if (position < size) {
             viewHolder.onBind(((List<MediaDevice>) (mController.getMediaDevices())).get(position),
                     position == 0 /* topMargin */, position == (size - 1) /* bottomMargin */,
@@ -89,11 +77,6 @@
 
     @Override
     public int getItemCount() {
-        mIncludeDynamicGroup = mController.getSelectedMediaDevice().size() > 1;
-        if (mController.isZeroMode() || mIncludeDynamicGroup) {
-            // Add extra one for "pair new" or dynamic group
-            return mController.getMediaDevices().size() + 1;
-        }
         return mController.getMediaDevices().size();
     }
 
@@ -115,16 +98,6 @@
             mStatusIcon.setVisibility(View.GONE);
             mTitleText.setTextColor(Utils.getColorStateListDefaultColor(mContext,
                     R.color.media_dialog_inactive_item_main_content));
-            if (currentlyConnected && mController.isActiveRemoteDevice(device)
-                    && mController.getSelectableMediaDevice().size() > 0) {
-                // Init active device layout
-                mAddIcon.setVisibility(View.VISIBLE);
-                mAddIcon.setTransitionAlpha(1);
-                mAddIcon.setOnClickListener(this::onEndItemClick);
-            } else {
-                // Init non-active device layout
-                mAddIcon.setVisibility(View.GONE);
-            }
             if (mCurrentActivePosition == position) {
                 mCurrentActivePosition = -1;
             }
@@ -158,6 +131,19 @@
                             true /* showSubtitle */, true /* showStatus */);
                     mSubTitleText.setText(R.string.media_output_dialog_connect_failed);
                     mContainerLayout.setOnClickListener(v -> onItemClick(v, device));
+                } else if (mController.getSelectedMediaDevice().size() > 1
+                        && isDeviceIncluded(mController.getSelectedMediaDevice(), device)) {
+                    mTitleText.setTextColor(Utils.getColorStateListDefaultColor(mContext,
+                            R.color.media_dialog_active_item_main_content));
+                    setSingleLineLayout(getItemTitle(device), true /* bFocused */,
+                            true /* showSeekBar */,
+                            false /* showProgressBar */, false /* showStatus */);
+                    mCheckBox.setVisibility(View.VISIBLE);
+                    mCheckBox.setChecked(true);
+                    mCheckBox.setOnCheckedChangeListener((buttonView, isChecked) -> {
+                        onCheckBoxClicked(false, device);
+                    });
+                    initSessionSeekbar();
                 } else if (!mController.hasAdjustVolumeUserRestriction() && currentlyConnected) {
                     mStatusIcon.setImageDrawable(
                             mContext.getDrawable(R.drawable.media_output_status_check));
@@ -168,6 +154,16 @@
                             false /* showProgressBar */, true /* showStatus */);
                     initSeekbar(device);
                     mCurrentActivePosition = position;
+                } else if (isDeviceIncluded(mController.getSelectableMediaDevice(), device)) {
+                    mCheckBox.setVisibility(View.VISIBLE);
+                    mCheckBox.setChecked(false);
+                    mCheckBox.setOnCheckedChangeListener((buttonView, isChecked) -> {
+                        onCheckBoxClicked(true, device);
+                    });
+                    setSingleLineLayout(getItemTitle(device), false /* bFocused */,
+                            false /* showSeekBar */,
+                            false /* showProgressBar */, false /* showStatus */);
+                    mContainerLayout.setOnClickListener(v -> onItemClick(v, device));
                 } else {
                     setSingleLineLayout(getItemTitle(device), false /* bFocused */);
                     mContainerLayout.setOnClickListener(v -> onItemClick(v, device));
@@ -181,7 +177,6 @@
                 mTitleText.setTextColor(Utils.getColorStateListDefaultColor(mContext,
                         R.color.media_dialog_inactive_item_main_content));
                 mCheckBox.setVisibility(View.GONE);
-                mAddIcon.setVisibility(View.GONE);
                 setSingleLineLayout(mContext.getText(R.string.media_output_dialog_pairing_new),
                         false /* bFocused */);
                 final Drawable d = mContext.getDrawable(R.drawable.ic_add);
@@ -189,28 +184,27 @@
                         Utils.getColorAccentDefaultColor(mContext), PorterDuff.Mode.SRC_IN));
                 mTitleIcon.setImageDrawable(d);
                 mContainerLayout.setOnClickListener(v -> onItemClick(CUSTOMIZED_ITEM_PAIR_NEW));
-            } else if (customizedItem == CUSTOMIZED_ITEM_DYNAMIC_GROUP) {
-                mTitleText.setTextColor(Utils.getColorStateListDefaultColor(mContext,
-                        R.color.media_dialog_active_item_main_content));
-                mConnectedItem = mContainerLayout;
-                mCheckBox.setVisibility(View.GONE);
-                if (mController.getSelectableMediaDevice().size() > 0) {
-                    mAddIcon.setVisibility(View.VISIBLE);
-                    mAddIcon.setTransitionAlpha(1);
-                    mAddIcon.setOnClickListener(this::onEndItemClick);
-                } else {
-                    mAddIcon.setVisibility(View.GONE);
-                }
-                mTitleIcon.setImageDrawable(getSpeakerDrawable());
-                final CharSequence sessionName = mController.getSessionName();
-                final CharSequence title = TextUtils.isEmpty(sessionName)
-                        ? mContext.getString(R.string.media_output_dialog_group) : sessionName;
-                setTwoLineLayout(title, true /* bFocused */, true /* showSeekBar */,
-                        false /* showProgressBar */, false /* showSubtitle */);
-                initSessionSeekbar();
             }
         }
 
+        private void onCheckBoxClicked(boolean isChecked, MediaDevice device) {
+            if (isChecked && isDeviceIncluded(mController.getSelectableMediaDevice(), device)) {
+                mController.addDeviceToPlayMedia(device);
+            } else if (!isChecked && isDeviceIncluded(mController.getDeselectableMediaDevice(),
+                    device)) {
+                mController.removeDeviceFromPlayMedia(device);
+            }
+        }
+
+        private boolean isDeviceIncluded(List<MediaDevice> deviceList, MediaDevice targetDevice) {
+            for (MediaDevice device : deviceList) {
+                if (TextUtils.equals(device.getId(), targetDevice.getId())) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
         private void onItemClick(View view, MediaDevice device) {
             if (mController.isTransferring()) {
                 return;
@@ -229,9 +223,5 @@
                 mController.launchBluetoothPairing();
             }
         }
-
-        private void onEndItemClick(View view) {
-            mController.launchMediaOutputGroupDialog(mMediaOutputDialog.getDialogView());
-        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
index bff792c..a8d30d4 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
@@ -118,7 +118,6 @@
         final TextView mTwoLineTitleText;
         final TextView mSubTitleText;
         final ImageView mTitleIcon;
-        final ImageView mAddIcon;
         final ProgressBar mProgressBar;
         final SeekBar mSeekBar;
         final RelativeLayout mTwoLineLayout;
@@ -137,7 +136,6 @@
             mTitleIcon = view.requireViewById(R.id.title_icon);
             mProgressBar = view.requireViewById(R.id.volume_indeterminate_progress);
             mSeekBar = view.requireViewById(R.id.volume_seekbar);
-            mAddIcon = view.requireViewById(R.id.add_icon);
             mStatusIcon = view.requireViewById(R.id.media_output_item_status);
             mCheckBox = view.requireViewById(R.id.check_box);
         }
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 4eee60c..83d581f 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
@@ -258,16 +258,15 @@
             drawable = mContext.getDrawable(com.android.internal.R.drawable.ic_bt_headphones_a2dp);
         }
         if (!(drawable instanceof BitmapDrawable)) {
-            setColorFilter(drawable,
-                    mLocalMediaManager.getCurrentConnectedDevice().getId().equals(device.getId()));
+            setColorFilter(drawable, isActiveItem(device));
         }
         return BluetoothUtils.createIconWithDrawable(drawable);
     }
 
-    void setColorFilter(Drawable drawable, boolean isConnected) {
+    void setColorFilter(Drawable drawable, boolean isActive) {
         final ColorStateList list =
                 mContext.getResources().getColorStateList(
-                        !hasAdjustVolumeUserRestriction() && isConnected && !isTransferring()
+                        isActive
                                 ? R.color.media_dialog_active_item_main_content
                                 : R.color.media_dialog_inactive_item_main_content,
                         mContext.getTheme());
@@ -275,6 +274,15 @@
                 PorterDuff.Mode.SRC_IN));
     }
 
+    boolean isActiveItem(MediaDevice device) {
+        boolean isConnected = mLocalMediaManager.getCurrentConnectedDevice().getId().equals(
+                device.getId());
+        boolean isSelectedDeviceInGroup = getSelectedMediaDevice().size() > 1
+                && getSelectedMediaDevice().contains(device);
+        return (!hasAdjustVolumeUserRestriction() && isConnected && !isTransferring())
+                || isSelectedDeviceInGroup;
+    }
+
     IconCompat getNotificationIcon() {
         if (TextUtils.isEmpty(mPackageName)) {
             return null;
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupAdapter.java
index 104ddf9..9b42b1d 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupAdapter.java
@@ -35,6 +35,7 @@
 /**
  * Adapter for media output dynamic group dialog.
  */
+//TODO: clear this class after new UI updated
 public class MediaOutputGroupAdapter extends MediaOutputBaseAdapter {
 
     private static final String TAG = "MediaOutputGroupAdapter";
@@ -96,7 +97,6 @@
         @Override
         void onBind(MediaDevice device, boolean topMargin, boolean bottomMargin, int position) {
             super.onBind(device, topMargin, bottomMargin, position);
-            mAddIcon.setVisibility(View.GONE);
             mCheckBox.setVisibility(View.VISIBLE);
             mCheckBox.setOnCheckedChangeListener((buttonView, isChecked) -> {
                 onCheckBoxClicked(isChecked, device);
@@ -131,7 +131,6 @@
                         false /* showSubtitle*/);
                 mTitleIcon.setImageDrawable(getSpeakerDrawable());
                 mCheckBox.setVisibility(View.GONE);
-                mAddIcon.setVisibility(View.GONE);
                 initSessionSeekbar();
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttChipState.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttChipState.kt
deleted file mode 100644
index 1f308a9a..0000000
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttChipState.kt
+++ /dev/null
@@ -1,67 +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.media.taptotransfer
-
-import androidx.annotation.StringRes
-import com.android.systemui.R
-import java.util.concurrent.Future
-
-/**
- * A class that stores all the information necessary to display the media tap-to-transfer chip in
- * certain states.
- *
- * This is a sealed class where each subclass represents a specific chip state. Each subclass can
- * contain additional information that is necessary for only that state.
- */
-sealed class MediaTttChipState(
-    /** A string resource for the text that the chip should display. */
-    @StringRes internal val chipText: Int,
-    /** The name of the other device involved in the transfer. */
-    internal val otherDeviceName: String
-)
-
-/**
- * A state representing that the two devices are close but not close enough to initiate a transfer.
- * The chip will instruct the user to move closer in order to initiate the transfer.
- */
-class MoveCloserToTransfer(
-    otherDeviceName: String
-) : MediaTttChipState(R.string.media_move_closer_to_transfer, otherDeviceName)
-
-/**
- * A state representing that a transfer has been initiated (but not completed).
- *
- * @property future a future that will be resolved when the transfer has either succeeded or failed.
- *   If the transfer succeeded, the future can optionally return an undo runnable (see
- *   [TransferSucceeded.undoRunnable]). [MediaTttChipController] is responsible for transitioning
- *   the chip to the [TransferSucceeded] state if the future resolves successfully.
- */
-class TransferInitiated(
-    otherDeviceName: String,
-    val future: Future<Runnable?>
-) : MediaTttChipState(R.string.media_transfer_playing, otherDeviceName)
-
-/**
- * A state representing that a transfer has been successfully completed.
- *
- * @property undoRunnable if present, the runnable that should be run to undo the transfer. We will
- *   show an Undo button on the chip if this runnable is present.
- */
-class TransferSucceeded(
-    otherDeviceName: String,
-    val undoRunnable: Runnable? = null
-) : MediaTttChipState(R.string.media_transfer_playing, otherDeviceName)
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt
index 663037c..5a86723 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt
@@ -16,10 +16,20 @@
 
 package com.android.systemui.media.taptotransfer
 
+import android.content.Context
+import android.graphics.Color
+import android.graphics.drawable.Icon
 import android.util.Log
 import androidx.annotation.VisibleForTesting
+import com.android.systemui.R
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.media.taptotransfer.receiver.MediaTttChipControllerReceiver
+import com.android.systemui.media.taptotransfer.receiver.ChipStateReceiver
+import com.android.systemui.media.taptotransfer.sender.MediaTttChipControllerSender
+import com.android.systemui.media.taptotransfer.sender.MoveCloserToTransfer
+import com.android.systemui.media.taptotransfer.sender.TransferInitiated
+import com.android.systemui.media.taptotransfer.sender.TransferSucceeded
 import com.android.systemui.statusbar.commandline.Command
 import com.android.systemui.statusbar.commandline.CommandRegistry
 import com.android.systemui.util.concurrency.DelayableExecutor
@@ -34,32 +44,59 @@
 @SysUISingleton
 class MediaTttCommandLineHelper @Inject constructor(
     commandRegistry: CommandRegistry,
-    private val mediaTttChipController: MediaTttChipController,
+    context: Context,
+    private val mediaTttChipControllerSender: MediaTttChipControllerSender,
+    private val mediaTttChipControllerReceiver: MediaTttChipControllerReceiver,
     @Main private val mainExecutor: DelayableExecutor,
 ) {
+    private val appIconDrawable =
+        Icon.createWithResource(context, R.drawable.ic_avatar_user).loadDrawable(context).also {
+            it.setTint(Color.YELLOW)
+        }
+
     init {
-        commandRegistry.registerCommand(ADD_CHIP_COMMAND_TAG) { AddChipCommand() }
-        commandRegistry.registerCommand(REMOVE_CHIP_COMMAND_TAG) { RemoveChipCommand() }
+        commandRegistry.registerCommand(
+            ADD_CHIP_COMMAND_SENDER_TAG) { AddChipCommandSender() }
+        commandRegistry.registerCommand(
+            REMOVE_CHIP_COMMAND_SENDER_TAG) { RemoveChipCommandSender() }
+        commandRegistry.registerCommand(
+            ADD_CHIP_COMMAND_RECEIVER_TAG) { AddChipCommandReceiver() }
+        commandRegistry.registerCommand(
+            REMOVE_CHIP_COMMAND_RECEIVER_TAG) { RemoveChipCommandReceiver() }
     }
 
-    inner class AddChipCommand : Command {
+    inner class AddChipCommandSender : Command {
         override fun execute(pw: PrintWriter, args: List<String>) {
             val otherDeviceName = args[0]
             when (args[1]) {
                 MOVE_CLOSER_TO_TRANSFER_COMMAND_NAME -> {
-                    mediaTttChipController.displayChip(MoveCloserToTransfer(otherDeviceName))
+                    mediaTttChipControllerSender.displayChip(
+                        MoveCloserToTransfer(
+                            appIconDrawable, APP_ICON_CONTENT_DESCRIPTION, otherDeviceName
+                        )
+                    )
                 }
                 TRANSFER_INITIATED_COMMAND_NAME -> {
                     val futureTask = FutureTask { fakeUndoRunnable }
-                    mediaTttChipController.displayChip(
-                        TransferInitiated(otherDeviceName, futureTask)
+                    mediaTttChipControllerSender.displayChip(
+                        TransferInitiated(
+                            appIconDrawable,
+                            APP_ICON_CONTENT_DESCRIPTION,
+                            otherDeviceName,
+                            futureTask
+                        )
                     )
                     mainExecutor.executeDelayed({ futureTask.run() }, FUTURE_WAIT_TIME)
 
                 }
                 TRANSFER_SUCCEEDED_COMMAND_NAME -> {
-                    mediaTttChipController.displayChip(
-                        TransferSucceeded(otherDeviceName, fakeUndoRunnable)
+                    mediaTttChipControllerSender.displayChip(
+                        TransferSucceeded(
+                            appIconDrawable,
+                            APP_ICON_CONTENT_DESCRIPTION,
+                            otherDeviceName,
+                            fakeUndoRunnable
+                        )
                     )
                 }
                 else -> {
@@ -73,18 +110,42 @@
         }
 
         override fun help(pw: PrintWriter) {
-            pw.println(
-                "Usage: adb shell cmd statusbar $ADD_CHIP_COMMAND_TAG <deviceName> <chipStatus>"
+            pw.println("Usage: adb shell cmd statusbar " +
+                    "$ADD_CHIP_COMMAND_SENDER_TAG <deviceName> <chipStatus>"
             )
         }
     }
 
-    inner class RemoveChipCommand : Command {
+    /** A command to REMOVE the media ttt chip on the SENDER device. */
+    inner class RemoveChipCommandSender : Command {
         override fun execute(pw: PrintWriter, args: List<String>) {
-            mediaTttChipController.removeChip()
+            mediaTttChipControllerSender.removeChip()
         }
         override fun help(pw: PrintWriter) {
-            pw.println("Usage: adb shell cmd statusbar $REMOVE_CHIP_COMMAND_TAG")
+            pw.println("Usage: adb shell cmd statusbar $REMOVE_CHIP_COMMAND_SENDER_TAG")
+        }
+    }
+
+
+    /** A command to DISPLAY the media ttt chip on the RECEIVER device. */
+    inner class AddChipCommandReceiver : Command {
+        override fun execute(pw: PrintWriter, args: List<String>) {
+            mediaTttChipControllerReceiver.displayChip(
+                ChipStateReceiver(appIconDrawable, APP_ICON_CONTENT_DESCRIPTION)
+            )
+        }
+        override fun help(pw: PrintWriter) {
+            pw.println("Usage: adb shell cmd statusbar $ADD_CHIP_COMMAND_RECEIVER_TAG")
+        }
+    }
+
+    /** A command to REMOVE the media ttt chip on the RECEIVER device. */
+    inner class RemoveChipCommandReceiver : Command {
+        override fun execute(pw: PrintWriter, args: List<String>) {
+            mediaTttChipControllerReceiver.removeChip()
+        }
+        override fun help(pw: PrintWriter) {
+            pw.println("Usage: adb shell cmd statusbar $REMOVE_CHIP_COMMAND_RECEIVER_TAG")
         }
     }
 
@@ -94,9 +155,13 @@
 }
 
 @VisibleForTesting
-const val ADD_CHIP_COMMAND_TAG = "media-ttt-chip-add"
+const val ADD_CHIP_COMMAND_SENDER_TAG = "media-ttt-chip-add-sender"
 @VisibleForTesting
-const val REMOVE_CHIP_COMMAND_TAG = "media-ttt-chip-remove"
+const val REMOVE_CHIP_COMMAND_SENDER_TAG = "media-ttt-chip-remove-sender"
+@VisibleForTesting
+const val ADD_CHIP_COMMAND_RECEIVER_TAG = "media-ttt-chip-add-receiver"
+@VisibleForTesting
+const val REMOVE_CHIP_COMMAND_RECEIVER_TAG = "media-ttt-chip-remove-receiver"
 @VisibleForTesting
 val MOVE_CLOSER_TO_TRANSFER_COMMAND_NAME = MoveCloserToTransfer::class.simpleName!!
 @VisibleForTesting
@@ -105,3 +170,5 @@
 val TRANSFER_SUCCEEDED_COMMAND_NAME = TransferSucceeded::class.simpleName!!
 
 private const val FUTURE_WAIT_TIME = 2000L
+private const val APP_ICON_CONTENT_DESCRIPTION = "Fake media app icon"
+private const val TAG = "MediaTapToTransferCli"
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/README.md b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/README.md
new file mode 100644
index 0000000..1145891
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/README.md
@@ -0,0 +1,11 @@
+# Media Tap-To-Transfer
+
+This package (and child packages) include code for the media tap-to-transfer feature, which
+allows users to easily transfer playing media between devices.
+
+In media transfer, there are two devices: the *sender* and the *receiver*. The sender device will
+start and stop media casts to the receiver device. On both devices, System UI will display a chip
+informing the user about the media cast occurring.
+
+This package is structured so that the sender code is in the sender package, the receiver code is
+in the receiver package, and code that's shared between them is in the common package.
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt
new file mode 100644
index 0000000..67721a5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.media.taptotransfer.common
+
+import android.annotation.LayoutRes
+import android.annotation.SuppressLint
+import android.content.Context
+import android.graphics.PixelFormat
+import android.view.Gravity
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import android.view.WindowManager
+import com.android.internal.widget.CachingIconView
+import com.android.systemui.R
+
+/**
+ * A superclass controller that provides common functionality for showing chips on the sender device
+ * and the receiver device.
+ *
+ * Subclasses need to override and implement [updateChipView], which is where they can control what
+ * gets displayed to the user.
+ */
+abstract class MediaTttChipControllerCommon<T : MediaTttChipState>(
+    private val context: Context,
+    private val windowManager: WindowManager,
+    @LayoutRes private val chipLayoutRes: Int
+) {
+    /** The window layout parameters we'll use when attaching the view to a window. */
+    @SuppressLint("WrongConstant") // We're allowed to use TYPE_VOLUME_OVERLAY
+    private val windowLayoutParams = WindowManager.LayoutParams().apply {
+        width = WindowManager.LayoutParams.WRAP_CONTENT
+        height = WindowManager.LayoutParams.WRAP_CONTENT
+        gravity = Gravity.TOP.or(Gravity.CENTER_HORIZONTAL)
+        type = WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY
+        flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+        title = "Media Tap-To-Transfer Chip View"
+        format = PixelFormat.TRANSLUCENT
+        setTrustedOverlay()
+    }
+
+    /** The chip view currently being displayed. Null if the chip is not being displayed. */
+    var chipView: ViewGroup? = null
+
+    /**
+     * Displays the chip with the current state.
+     *
+     * This method handles inflating and attaching the view, then delegates to [updateChipView] to
+     * display the correct information in the chip.
+     */
+    fun displayChip(chipState: T) {
+        val oldChipView = chipView
+        if (chipView == null) {
+            chipView = LayoutInflater
+                .from(context)
+                .inflate(chipLayoutRes, null) as ViewGroup
+        }
+        val currentChipView = chipView!!
+
+        updateChipView(chipState, currentChipView)
+
+        // Add view if necessary
+        if (oldChipView == null) {
+            windowManager.addView(chipView, windowLayoutParams)
+        }
+    }
+
+
+    /** Hides the chip. */
+    fun removeChip() {
+        if (chipView == null) { return }
+        windowManager.removeView(chipView)
+        chipView = null
+    }
+
+    /**
+     * A method implemented by subclasses to update [currentChipView] based on [chipState].
+     */
+    abstract fun updateChipView(chipState: T, currentChipView: ViewGroup)
+
+    /**
+     * An internal method to set the icon on the view.
+     *
+     * This is in the common superclass since both the sender and the receiver show an icon.
+     */
+    internal fun setIcon(chipState: T, currentChipView: ViewGroup) {
+        currentChipView.findViewById<CachingIconView>(R.id.app_icon).apply {
+            this.setImageDrawable(chipState.appIconDrawable)
+            this.contentDescription = chipState.appIconContentDescription
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipState.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipState.kt
new file mode 100644
index 0000000..c510cbb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipState.kt
@@ -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.
+ */
+
+package com.android.systemui.media.taptotransfer.common
+
+import android.graphics.drawable.Drawable
+
+/**
+ * A superclass chip state that will be subclassed by the sender chip and receiver chip.
+ *
+ * @property appIconDrawable a drawable representing the icon of the app playing the media.
+ * @property appIconContentDescription a string to use as the content description for the icon.
+ */
+open class MediaTttChipState(
+    internal val appIconDrawable: Drawable,
+    internal val appIconContentDescription: String
+)
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/ChipStateReceiver.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/ChipStateReceiver.kt
new file mode 100644
index 0000000..df6b934
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/ChipStateReceiver.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.media.taptotransfer.receiver
+
+import android.graphics.drawable.Drawable
+import com.android.systemui.media.taptotransfer.common.MediaTttChipState
+
+/**
+ * A class that stores all the information necessary to display the media tap-to-transfer chip on
+ * the receiver device.
+ */
+class ChipStateReceiver(
+    appIconDrawable: Drawable,
+    appIconContentDescription: String
+) : MediaTttChipState(appIconDrawable, appIconContentDescription)
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
new file mode 100644
index 0000000..1780954
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.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.systemui.media.taptotransfer.receiver
+
+import android.content.Context
+import android.view.ViewGroup
+import android.view.WindowManager
+import com.android.systemui.R
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.media.taptotransfer.common.MediaTttChipControllerCommon
+import javax.inject.Inject
+
+/**
+ * A controller to display and hide the Media Tap-To-Transfer chip on the **receiving** device.
+ *
+ * This chip is shown when a user is transferring media to/from a sending device and this device.
+ */
+@SysUISingleton
+class MediaTttChipControllerReceiver @Inject constructor(
+    context: Context,
+    windowManager: WindowManager,
+) : MediaTttChipControllerCommon<ChipStateReceiver>(
+    context, windowManager, R.layout.media_ttt_chip_receiver
+) {
+
+    override fun updateChipView(chipState: ChipStateReceiver, currentChipView: ViewGroup) {
+        setIcon(chipState, currentChipView)
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt
new file mode 100644
index 0000000..b1f6faa
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt
@@ -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.media.taptotransfer.sender
+
+import android.graphics.drawable.Drawable
+import androidx.annotation.StringRes
+import com.android.systemui.R
+import com.android.systemui.media.taptotransfer.common.MediaTttChipState
+import java.util.concurrent.Future
+
+/**
+ * A class that stores all the information necessary to display the media tap-to-transfer chip on
+ * the sender device.
+ *
+ * This is a sealed class where each subclass represents a specific chip state. Each subclass can
+ * contain additional information that is necessary for only that state.
+ *
+ * @property chipText a string resource for the text that the chip should display.
+ * @property otherDeviceName the name of the other device involved in the transfer.
+ */
+sealed class ChipStateSender(
+    appIconDrawable: Drawable,
+    appIconContentDescription: String,
+    @StringRes internal val chipText: Int,
+    internal val otherDeviceName: String,
+) : MediaTttChipState(appIconDrawable, appIconContentDescription)
+
+/**
+ * A state representing that the two devices are close but not close enough to initiate a transfer.
+ * The chip will instruct the user to move closer in order to initiate the transfer.
+ */
+class MoveCloserToTransfer(
+    appIconDrawable: Drawable,
+    appIconContentDescription: String,
+    otherDeviceName: String,
+) : ChipStateSender(
+    appIconDrawable,
+    appIconContentDescription,
+    R.string.media_move_closer_to_transfer,
+    otherDeviceName
+)
+
+/**
+ * A state representing that a transfer has been initiated (but not completed).
+ *
+ * @property future a future that will be resolved when the transfer has either succeeded or failed.
+ *   If the transfer succeeded, the future can optionally return an undo runnable (see
+ *   [TransferSucceeded.undoRunnable]). [MediaTttChipControllerSender] is responsible for transitioning
+ *   the chip to the [TransferSucceeded] state if the future resolves successfully.
+ */
+class TransferInitiated(
+    appIconDrawable: Drawable,
+    appIconContentDescription: String,
+    otherDeviceName: String,
+    val future: Future<Runnable?>
+) : ChipStateSender(
+    appIconDrawable,
+    appIconContentDescription,
+    R.string.media_transfer_playing,
+    otherDeviceName
+)
+
+/**
+ * A state representing that a transfer has been successfully completed.
+ *
+ * @property undoRunnable if present, the runnable that should be run to undo the transfer. We will
+ *   show an Undo button on the chip if this runnable is present.
+ */
+class TransferSucceeded(
+    appIconDrawable: Drawable,
+    appIconContentDescription: String,
+    otherDeviceName: String,
+    val undoRunnable: Runnable? = null
+) : ChipStateSender(appIconDrawable,
+    appIconContentDescription,
+    R.string.media_transfer_playing,
+    otherDeviceName
+)
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttChipController.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt
similarity index 60%
rename from packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttChipController.kt
rename to packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt
index baa469d..77d3d70 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttChipController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt
@@ -14,65 +14,40 @@
  * limitations under the License.
  */
 
-package com.android.systemui.media.taptotransfer
+package com.android.systemui.media.taptotransfer.sender
 
-import android.annotation.SuppressLint
 import android.content.Context
-import android.graphics.PixelFormat
-import android.view.Gravity
-import android.view.LayoutInflater
 import android.view.View
+import android.view.ViewGroup
 import android.view.WindowManager
-import android.widget.LinearLayout
 import android.widget.TextView
 import com.android.systemui.R
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.media.taptotransfer.common.MediaTttChipControllerCommon
 import java.util.concurrent.Executor
 import java.util.concurrent.TimeUnit
 import javax.inject.Inject
 
-const val TAG = "MediaTapToTransfer"
-
 /**
- * A controller to display and hide the Media Tap-To-Transfer chip. This chip is shown when a user
- * is currently playing media on a local "media cast sender" device (e.g. a phone) and gets close
- * enough to a "media cast receiver" device (e.g. a tablet). This chip encourages the user to
- * transfer the media from the sender device to the receiver device.
+ * A controller to display and hide the Media Tap-To-Transfer chip on the **sending** device. This
+ * chip is shown when a user is transferring media to/from this device and a receiver device.
  */
 @SysUISingleton
-class MediaTttChipController @Inject constructor(
-    private val context: Context,
-    private val windowManager: WindowManager,
+class MediaTttChipControllerSender @Inject constructor(
+    context: Context,
+    windowManager: WindowManager,
     @Main private val mainExecutor: Executor,
     @Background private val backgroundExecutor: Executor,
+) : MediaTttChipControllerCommon<ChipStateSender>(
+    context, windowManager, R.layout.media_ttt_chip
 ) {
 
-    @SuppressLint("WrongConstant") // We're allowed to use TYPE_VOLUME_OVERLAY
-    private val windowLayoutParams = WindowManager.LayoutParams().apply {
-        width = WindowManager.LayoutParams.WRAP_CONTENT
-        height = WindowManager.LayoutParams.WRAP_CONTENT
-        gravity = Gravity.TOP.or(Gravity.CENTER_HORIZONTAL)
-        type = WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY
-        flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
-        title = "Media Tap-To-Transfer Chip View"
-        format = PixelFormat.TRANSLUCENT
-        setTrustedOverlay()
-    }
-
-    /** The chip view currently being displayed. Null if the chip is not being displayed. */
-    private var chipView: LinearLayout? = null
-
     /** Displays the chip view for the given state. */
-    fun displayChip(chipState: MediaTttChipState) {
-        val oldChipView = chipView
-        if (chipView == null) {
-            chipView = LayoutInflater
-                .from(context)
-                .inflate(R.layout.media_ttt_chip, null) as LinearLayout
-        }
-        val currentChipView = chipView!!
+    override fun updateChipView(chipState: ChipStateSender, currentChipView: ViewGroup) {
+        // App icon
+        setIcon(chipState, currentChipView)
 
         // Text
         currentChipView.requireViewById<TextView>(R.id.text).apply {
@@ -102,18 +77,6 @@
         if (chipState is TransferInitiated) {
             addFutureCallback(chipState)
         }
-
-        // Add view if necessary
-        if (oldChipView == null) {
-            windowManager.addView(chipView, windowLayoutParams)
-        }
-    }
-
-    /** Hides the chip. */
-    fun removeChip() {
-        if (chipView == null) { return }
-        windowManager.removeView(chipView)
-        chipView = null
     }
 
     /**
@@ -128,7 +91,14 @@
                 val undoRunnable = chipState.future.get(TRANSFER_TIMEOUT_SECONDS, TimeUnit.SECONDS)
                 // Make UI changes on the main thread
                 mainExecutor.execute {
-                    displayChip(TransferSucceeded(chipState.otherDeviceName, undoRunnable))
+                    displayChip(
+                        TransferSucceeded(
+                            chipState.appIconDrawable,
+                            chipState.appIconContentDescription,
+                            chipState.otherDeviceName,
+                            undoRunnable
+                        )
+                    )
                 }
             } catch (ex: Exception) {
                 // TODO(b/203800327): Maybe show a failure chip here if UX decides we need one.
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index 3e2da72..6d1f8f7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -30,6 +30,7 @@
 import com.android.systemui.qs.QSPanelControllerBase.TileRecord;
 
 import java.util.ArrayList;
+import java.util.List;
 import java.util.Set;
 
 public class PagedTileLayout extends ViewPager implements QSTileLayout {
@@ -332,6 +333,18 @@
         mPageListener = listener;
     }
 
+    public List<String> getSpecsForPage(int page) {
+        ArrayList<String> out = new ArrayList<>();
+        if (page < 0) return out;
+        int perPage = mPages.get(0).maxTiles();
+        int startOfPage = page * perPage;
+        int endOfPage = (page + 1) * perPage;
+        for (int i = startOfPage; i < endOfPage && i < mTiles.size(); i++) {
+            out.add(mTiles.get(i).tile.getTileSpec());
+        }
+        return out;
+    }
+
     private void distributeTiles() {
         emptyAndInflateOrRemovePages();
 
@@ -491,6 +504,11 @@
         return currentPage.mRecords.size();
     }
 
+    public int getNumTilesFirstPage() {
+        if (mPages.size() == 0) return 0;
+        return mPages.get(0).mRecords.size();
+    }
+
     public void startTileReveal(Set<String> tileSpecs, final Runnable postAnimation) {
         if (tileSpecs.isEmpty() || mPages.size() < 2 || getScrollX() != 0 || !beginFakeDrag()) {
             // Do not start the reveal animation unless there are tiles to animate, multiple
@@ -556,8 +574,9 @@
                     updateSelected();
                     if (mPageIndicator == null) return;
                     if (mPageListener != null) {
+                        int pageNumber = isLayoutRtl() ? mPages.size() - 1 - position : position;
                         mPageListener.onPageChanged(isLayoutRtl() ? position == mPages.size() - 1
-                                : position == 0);
+                                : position == 0, pageNumber);
                     }
                 }
 
@@ -575,8 +594,12 @@
                     mPageIndicatorPosition = position + positionOffset;
                     mPageIndicator.setLocation(mPageIndicatorPosition);
                     if (mPageListener != null) {
+                        int pageNumber = isLayoutRtl() ? mPages.size() - 1 - position : position;
                         mPageListener.onPageChanged(positionOffsetPixels == 0 &&
-                                (isLayoutRtl() ? position == mPages.size() - 1 : position == 0));
+                                (isLayoutRtl() ? position == mPages.size() - 1 : position == 0),
+                                // Send only valid page number on integer pages
+                                positionOffsetPixels == 0 ? pageNumber : PageListener.INVALID_PAGE
+                        );
                     }
                 }
 
@@ -626,6 +649,7 @@
     };
 
     public interface PageListener {
-        void onPageChanged(boolean isFirst);
+        int INVALID_PAGE = -1;
+        void onPageChanged(boolean isFirst, int pageNumber);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index 44d5e21..6c7d6e0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -20,6 +20,8 @@
 import android.animation.TimeInterpolator;
 import android.animation.ValueAnimator;
 import android.util.Log;
+import android.util.Pair;
+import android.util.SparseArray;
 import android.view.View;
 import android.view.View.OnAttachStateChangeListener;
 import android.view.View.OnLayoutChangeListener;
@@ -57,11 +59,14 @@
     private static final String ALLOW_FANCY_ANIMATION = "sysui_qs_fancy_anim";
     private static final String MOVE_FULL_ROWS = "sysui_qs_move_whole_rows";
 
-    public static final float EXPANDED_TILE_DELAY = .86f;
+    private static final float EXPANDED_TILE_DELAY = .86f;
+    //Non first page delays
+    private static final float QS_TILE_LABEL_FADE_OUT_START = 0.15f;
+    private static final float QS_TILE_LABEL_FADE_OUT_END = 0.7f;
+    private static final float QQS_FADE_IN_INTERVAL = 0.1f;
+
     public static final float SHORT_PARALLAX_AMOUNT = 0.1f;
-    private static final long QQS_FADE_IN_DURATION = 200L;
-    // Fade out faster than fade in to finish before QQS hides.
-    private static final long QQS_FADE_OUT_DURATION = 50L;
+
 
     /**
      * List of all views that will be reset when clearing animation state
@@ -86,33 +91,54 @@
     private PagedTileLayout mPagedLayout;
 
     private boolean mOnFirstPage = true;
-    private QSExpansionPathInterpolator mQSExpansionPathInterpolator;
+    private int mCurrentPage = 0;
+    private final QSExpansionPathInterpolator mQSExpansionPathInterpolator;
+    // Animator for elements in the first page, including secondary labels and qqs brightness
+    // slider, as well as animating the alpha of the QS tile layout (as we are tracking QQS tiles)
     private TouchAnimator mFirstPageAnimator;
-    private TouchAnimator mFirstPageDelayedAnimator;
+    // TranslationX animator for QQS/QS tiles
     private TouchAnimator mTranslationXAnimator;
+    // TranslationY animator for QS tiles (and their components) in the first page
     private TouchAnimator mTranslationYAnimator;
-    private TouchAnimator mNonfirstPageAnimator;
-    private TouchAnimator mNonfirstPageDelayedAnimator;
+    // TranslationY animator for QQS tiles (and their components)
+    private TouchAnimator mQQSTranslationYAnimator;
+    // Animates alpha of permanent views (QS tile layout, QQS tiles) when not in first page
+    private TouchAnimator mNonfirstPageAlphaAnimator;
+    // TranslatesY the QS Tile layout using QS.getHeightDiff()
+    private TouchAnimator mQSTileLayoutTranslatorAnimator;
     // This animates fading of SecurityFooter and media divider
     private TouchAnimator mAllPagesDelayedAnimator;
+    // Animator for brightness slider(s)
     private TouchAnimator mBrightnessAnimator;
+    // Animator for Footer actions in QQS
     private TouchAnimator mQQSFooterActionsAnimator;
+    // Height animator for QQS tiles (height changing from QQS size to QS size)
     private HeightExpansionAnimator mQQSTileHeightAnimator;
-    private HeightExpansionAnimator mOtherTilesExpandAnimator;
+    // Height animator for QS tile in first page but not in QQS, to present the illusion that they
+    // are expanding alongside the QQS tiles
+    private HeightExpansionAnimator mOtherFirstPageTilesHeightAnimator;
+    // Pair of animators for each non first page. The creation is delayed until the user first
+    // scrolls to that page, in order to get the proper measures and layout.
+    private final SparseArray<Pair<HeightExpansionAnimator, TouchAnimator>>
+            mNonFirstPageQSAnimators = new SparseArray<>();
 
     private boolean mNeedsAnimatorUpdate = false;
-    private boolean mToShowing;
     private boolean mOnKeyguard;
 
     private boolean mAllowFancy;
     private boolean mFullRows;
     private int mNumQuickTiles;
+    private int mLastQQSTileHeight;
     private float mLastPosition;
     private final QSTileHost mHost;
     private final Executor mExecutor;
     private final TunerService mTunerService;
     private boolean mShowCollapsedOnKeyguard;
     private boolean mTranslateWhileExpanding;
+    private int mQQSTop;
+
+    private int[] mTmpLoc1 = new int[2];
+    private int[] mTmpLoc2 = new int[2];
 
     @Inject
     public QSAnimator(QS qs, QuickQSPanel quickPanel, QuickStatusBarHeader quickStatusBarHeader,
@@ -213,8 +239,19 @@
         updateAnimators();
     }
 
+    private void addNonFirstPageAnimators(int page) {
+        Pair<HeightExpansionAnimator, TouchAnimator> pair = createSecondaryPageAnimators(page);
+        mNonFirstPageQSAnimators.put(page, pair);
+    }
+
     @Override
-    public void onPageChanged(boolean isFirst) {
+    public void onPageChanged(boolean isFirst, int currentPage) {
+        if (currentPage != INVALID_PAGE && mCurrentPage != currentPage) {
+            mCurrentPage = currentPage;
+            if (!isFirst && !mNonFirstPageQSAnimators.contains(currentPage)) {
+                addNonFirstPageAnimators(currentPage);
+            }
+        }
         if (mOnFirstPage == isFirst) return;
         if (!isFirst) {
             clearAnimationState();
@@ -230,7 +267,8 @@
             int yOffset,
             int[] temp,
             TouchAnimator.Builder animatorBuilderX,
-            TouchAnimator.Builder animatorBuilderY
+            TouchAnimator.Builder animatorBuilderY,
+            TouchAnimator.Builder qqsAnimatorBuilderY
     ) {
         getRelativePosition(temp, qqsView, commonParent);
         int qqsPosX = temp[0];
@@ -243,7 +281,7 @@
         animatorBuilderX.addFloat(qqsView, "translationX", 0, xDiff);
         animatorBuilderX.addFloat(qsView, "translationX", -xDiff, 0);
         int yDiff = qsPosY - qqsPosY - yOffset;
-        animatorBuilderY.addFloat(qqsView, "translationY", 0, yDiff);
+        qqsAnimatorBuilderY.addFloat(qqsView, "translationY", 0, yDiff);
         animatorBuilderY.addFloat(qsView, "translationY", -yDiff, 0);
         mAllViews.add(qqsView);
         mAllViews.add(qsView);
@@ -253,40 +291,47 @@
         mNeedsAnimatorUpdate = false;
         TouchAnimator.Builder firstPageBuilder = new Builder();
         TouchAnimator.Builder translationYBuilder = new Builder();
+        TouchAnimator.Builder qqsTranslationYBuilder = new Builder();
         TouchAnimator.Builder translationXBuilder = new Builder();
+        TouchAnimator.Builder nonFirstPageAlphaBuilder = new Builder();
 
         Collection<QSTile> tiles = mHost.getTiles();
         int count = 0;
-        int[] loc1 = new int[2];
-        int[] loc2 = new int[2];
 
         clearAnimationState();
+        mNonFirstPageQSAnimators.clear();
         mAllViews.clear();
         mAnimatedQsViews.clear();
         mQQSTileHeightAnimator = null;
-        mOtherTilesExpandAnimator = null;
+        mOtherFirstPageTilesHeightAnimator = null;
 
         mNumQuickTiles = mQuickQsPanel.getNumQuickTiles();
 
         QSTileLayout tileLayout = mQsPanelController.getTileLayout();
         mAllViews.add((View) tileLayout);
-        int height = mQs.getView() != null ? mQs.getView().getMeasuredHeight() : 0;
-        int heightDiff = height - mQs.getHeader().getBottom()
-                + mQs.getHeader().getPaddingBottom();
+        int heightDiff = mQs.getHeightDiff();
         if (!mTranslateWhileExpanding) {
             heightDiff *= SHORT_PARALLAX_AMOUNT;
         }
-        firstPageBuilder.addFloat(tileLayout, "translationY", heightDiff, 0);
+        mQSTileLayoutTranslatorAnimator = new Builder()
+                .addFloat(tileLayout, "translationY", heightDiff, 0)
+                .build();
 
-        int qqsTileHeight = 0;
+        mLastQQSTileHeight = 0;
 
         if (mQsPanelController.areThereTiles()) {
             for (QSTile tile : tiles) {
                 QSTileView tileView = mQsPanelController.getTileView(tile);
+
                 if (tileView == null) {
                     Log.e(TAG, "tileView is null " + tile.getTileSpec());
                     continue;
                 }
+                // Only animate tiles in the first page
+                if (mPagedLayout != null && count >= mPagedLayout.getNumTilesFirstPage()) {
+                    break;
+                }
+
                 final View tileIcon = tileView.getIcon().getIconView();
                 View view = mQs.getView();
 
@@ -297,16 +342,16 @@
                     QSTileView quickTileView = mQuickQSPanelController.getTileView(tile);
                     if (quickTileView == null) continue;
 
-                    getRelativePosition(loc1, quickTileView, view);
-                    getRelativePosition(loc2, tileView, view);
-                    int yOffset = loc2[1] - loc1[1];
-                    int xOffset = loc2[0] - loc1[0];
+                    getRelativePosition(mTmpLoc1, quickTileView, view);
+                    getRelativePosition(mTmpLoc2, tileView, view);
+                    int yOffset = mTmpLoc2[1] - mTmpLoc1[1];
+                    int xOffset = mTmpLoc2[0] - mTmpLoc1[0];
 
                     // Offset the translation animation on the views
                     // (that goes from 0 to getOffsetTranslation)
                     int offsetWithQSBHTranslation =
                             yOffset - mQuickStatusBarHeader.getOffsetTranslation();
-                    translationYBuilder.addFloat(quickTileView, "translationY", 0,
+                    qqsTranslationYBuilder.addFloat(quickTileView, "translationY", 0,
                             offsetWithQSBHTranslation);
                     translationYBuilder.addFloat(tileView, "translationY",
                             -offsetWithQSBHTranslation, 0);
@@ -317,7 +362,7 @@
                     if (mQQSTileHeightAnimator == null) {
                         mQQSTileHeightAnimator = new HeightExpansionAnimator(this,
                                 quickTileView.getMeasuredHeight(), tileView.getMeasuredHeight());
-                        qqsTileHeight = quickTileView.getMeasuredHeight();
+                        mLastQQSTileHeight = quickTileView.getMeasuredHeight();
                     }
 
                     mQQSTileHeightAnimator.addView(quickTileView);
@@ -329,9 +374,10 @@
                             view,
                             xOffset,
                             yOffset,
-                            loc1,
+                            mTmpLoc1,
                             translationXBuilder,
-                            translationYBuilder
+                            translationYBuilder,
+                            qqsTranslationYBuilder
                     );
 
                     // Label containers
@@ -341,9 +387,10 @@
                             view,
                             xOffset,
                             yOffset,
-                            loc1,
+                            mTmpLoc1,
                             translationXBuilder,
-                            translationYBuilder
+                            translationYBuilder,
+                            qqsTranslationYBuilder
                     );
 
                     // Secondary icon
@@ -353,12 +400,15 @@
                             view,
                             xOffset,
                             yOffset,
-                            loc1,
+                            mTmpLoc1,
                             translationXBuilder,
-                            translationYBuilder
+                            translationYBuilder,
+                            qqsTranslationYBuilder
                     );
 
                     firstPageBuilder.addFloat(quickTileView.getSecondaryLabel(), "alpha", 0, 1);
+                    nonFirstPageAlphaBuilder
+                            .addFloat(quickTileView.getSecondaryLabel(), "alpha", 0, 0);
 
                     mAnimatedQsViews.add(tileView);
                     mAllViews.add(quickTileView);
@@ -373,16 +423,17 @@
                     // expanding from.
                     SideLabelTileLayout qqsLayout =
                             (SideLabelTileLayout) mQuickQsPanel.getTileLayout();
-                    getRelativePosition(loc1, qqsLayout, view);
-                    getRelativePosition(loc2, tileView, view);
-                    int diff = loc2[1] - (loc1[1] + qqsLayout.getPhantomTopPosition(count));
+                    getRelativePosition(mTmpLoc1, qqsLayout, view);
+                    mQQSTop = mTmpLoc1[1];
+                    getRelativePosition(mTmpLoc2, tileView, view);
+                    int diff = mTmpLoc2[1] - (mTmpLoc1[1] + qqsLayout.getPhantomTopPosition(count));
                     translationYBuilder.addFloat(tileView, "translationY", -diff, 0);
-                    if (mOtherTilesExpandAnimator == null) {
-                        mOtherTilesExpandAnimator =
+                    if (mOtherFirstPageTilesHeightAnimator == null) {
+                        mOtherFirstPageTilesHeightAnimator =
                                 new HeightExpansionAnimator(
-                                        this, qqsTileHeight, tileView.getMeasuredHeight());
+                                        this, mLastQQSTileHeight, tileView.getMeasuredHeight());
                     }
-                    mOtherTilesExpandAnimator.addView(tileView);
+                    mOtherFirstPageTilesHeightAnimator.addView(tileView);
                     tileView.setClipChildren(true);
                     tileView.setClipToPadding(true);
                     firstPageBuilder.addFloat(tileView.getSecondaryLabel(), "alpha", 0, 1);
@@ -392,18 +443,19 @@
                 mAllViews.add(tileView);
                 count++;
             }
+            if (mCurrentPage != 0) {
+                addNonFirstPageAnimators(mCurrentPage);
+            }
         }
 
         if (mAllowFancy) {
             animateBrightnessSlider(firstPageBuilder);
 
             mFirstPageAnimator = firstPageBuilder
+                    // Fade in the tiles/labels as we reach the final position.
+                    .addFloat(tileLayout, "alpha", 0, 1)
                     .setListener(this)
                     .build();
-            // Fade in the tiles/labels as we reach the final position.
-            Builder builder = new Builder()
-                    .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
@@ -411,9 +463,8 @@
                 updateQQSFooterAnimation();
             }
 
-
             // Fade in the security footer and the divider as we reach the final position
-            builder = new Builder().setStartDelay(EXPANDED_TILE_DELAY);
+            Builder builder = new Builder().setStartDelay(EXPANDED_TILE_DELAY);
             builder.addFloat(mSecurityFooter.getView(), "alpha", 0, 1);
             if (mQsPanelController.shouldUseHorizontalLayout()
                     && mQsPanelController.mMediaHost.hostView != null) {
@@ -425,26 +476,100 @@
             mAllPagesDelayedAnimator = builder.build();
             mAllViews.add(mSecurityFooter.getView());
             translationYBuilder.setInterpolator(mQSExpansionPathInterpolator.getYInterpolator());
+            qqsTranslationYBuilder.setInterpolator(mQSExpansionPathInterpolator.getYInterpolator());
             translationXBuilder.setInterpolator(mQSExpansionPathInterpolator.getXInterpolator());
+            if (mOnFirstPage) {
+                // Only recreate this animator if we're in the first page. That way we know that
+                // the first page is attached and has the proper positions/measures.
+                mQQSTranslationYAnimator = qqsTranslationYBuilder.build();
+            }
             mTranslationYAnimator = translationYBuilder.build();
             mTranslationXAnimator = translationXBuilder.build();
             if (mQQSTileHeightAnimator != null) {
                 mQQSTileHeightAnimator.setInterpolator(
                         mQSExpansionPathInterpolator.getYInterpolator());
             }
-            if (mOtherTilesExpandAnimator != null) {
-                mOtherTilesExpandAnimator.setInterpolator(
+            if (mOtherFirstPageTilesHeightAnimator != null) {
+                mOtherFirstPageTilesHeightAnimator.setInterpolator(
                         mQSExpansionPathInterpolator.getYInterpolator());
             }
         }
-        mNonfirstPageAnimator = new TouchAnimator.Builder()
+        mNonfirstPageAlphaAnimator = nonFirstPageAlphaBuilder
                 .addFloat(mQuickQsPanel, "alpha", 1, 0)
+                .addFloat(tileLayout, "alpha", 0, 1)
                 .setListener(mNonFirstPageListener)
-                .setEndDelay(.5f)
+                .setEndDelay(1 - QQS_FADE_IN_INTERVAL)
                 .build();
-        mNonfirstPageDelayedAnimator = new TouchAnimator.Builder()
-                .setStartDelay(.14f)
-                .addFloat(tileLayout, "alpha", 0, 1).build();
+    }
+
+    private Pair<HeightExpansionAnimator, TouchAnimator> createSecondaryPageAnimators(int page) {
+        if (mPagedLayout == null) return null;
+        HeightExpansionAnimator animator = null;
+        TouchAnimator.Builder builder = new Builder()
+                .setInterpolator(mQSExpansionPathInterpolator.getYInterpolator());
+        TouchAnimator.Builder alphaDelayedBuilder = new Builder()
+                .setStartDelay(QS_TILE_LABEL_FADE_OUT_START)
+                .setEndDelay(QS_TILE_LABEL_FADE_OUT_END);
+        SideLabelTileLayout qqsLayout = (SideLabelTileLayout) mQuickQsPanel.getTileLayout();
+        View view = mQs.getView();
+        List<String> specs = mPagedLayout.getSpecsForPage(page);
+
+        int row = -1;
+        int lastTileTop = -1;
+
+        for (int i = 0; i < specs.size(); i++) {
+            QSTileView tileView = mQsPanelController.getTileView(specs.get(i));
+            getRelativePosition(mTmpLoc2, tileView, view);
+            int diff = mTmpLoc2[1] - (mQQSTop + qqsLayout.getPhantomTopPosition(i));
+            builder.addFloat(tileView, "translationY", -diff, 0);
+            // The different elements in the tile should be centered, so maintain them centered
+            int centerDiff = (tileView.getMeasuredHeight() - mLastQQSTileHeight) / 2;
+            builder.addFloat(tileView.getIcon(), "translationY", -centerDiff, 0);
+            builder.addFloat(tileView.getSecondaryIcon(), "translationY", -centerDiff, 0);
+            // The labels have different apparent size in QQS vs QS (no secondary label), so the
+            // translation needs to account for that.
+            int labelDiff = centerDiff - tileView.getSecondaryLabel().getMeasuredHeight() / 2;
+            builder.addFloat(tileView.getLabelContainer(), "translationY", -labelDiff, 0);
+            builder.addFloat(tileView.getSecondaryLabel(), "alpha", 0, 0.3f, 1);
+
+            alphaDelayedBuilder.addFloat(tileView.getLabelContainer(), "alpha", 0, 1);
+            alphaDelayedBuilder.addFloat(tileView.getIcon(), "alpha", 0, 1);
+            alphaDelayedBuilder.addFloat(tileView.getSecondaryIcon(), "alpha", 0, 1);
+
+            final int tileTop = tileView.getTop();
+            if (tileTop != lastTileTop) {
+                row++;
+                lastTileTop = tileTop;
+            }
+            if (i >= mQuickQsPanel.getTileLayout().getNumVisibleTiles() && row >= 2) {
+                // Fade completely the tiles in rows below the ones that will merge into QQS.
+                // args is an array of 0s where the length is the current row index (at least third
+                // row)
+                final float[] args = new float[row];
+                args[args.length - 1] = 1f;
+                builder.addFloat(tileView, "alpha", args);
+            } else {
+                // For all the other rows, fade them a bit
+                builder.addFloat(tileView, "alpha", 0.6f, 1);
+            }
+
+            if (animator == null) {
+                animator = new HeightExpansionAnimator(
+                                this, mLastQQSTileHeight, tileView.getMeasuredHeight());
+                animator.setInterpolator(mQSExpansionPathInterpolator.getYInterpolator());
+            }
+            animator.addView(tileView);
+
+            tileView.setClipChildren(true);
+            tileView.setClipToPadding(true);
+            mAllViews.add(tileView);
+            mAllViews.add(tileView.getSecondaryLabel());
+            mAllViews.add(tileView.getIcon());
+            mAllViews.add(tileView.getSecondaryIcon());
+            mAllViews.add(tileView.getLabelContainer());
+        }
+        builder.addFloat(alphaDelayedBuilder.build(), "position", 0, 1);
+        return new Pair<>(animator, builder.build());
     }
 
     private void animateBrightnessSlider(Builder firstPageBuilder) {
@@ -542,30 +667,36 @@
             }
         }
         mLastPosition = position;
-        if (mOnFirstPage && mAllowFancy) {
+        if (!mAllowFancy) return;
+        if (mOnFirstPage) {
             mQuickQsPanel.setAlpha(1);
             mFirstPageAnimator.setPosition(position);
-            mFirstPageDelayedAnimator.setPosition(position);
             mTranslationYAnimator.setPosition(position);
             mTranslationXAnimator.setPosition(position);
-            if (mQQSTileHeightAnimator != null) {
-                mQQSTileHeightAnimator.setPosition(position);
-            }
-            if (mOtherTilesExpandAnimator != null) {
-                mOtherTilesExpandAnimator.setPosition(position);
+            if (mOtherFirstPageTilesHeightAnimator != null) {
+                mOtherFirstPageTilesHeightAnimator.setPosition(position);
             }
         } else {
-            mNonfirstPageAnimator.setPosition(position);
-            mNonfirstPageDelayedAnimator.setPosition(position);
+            mNonfirstPageAlphaAnimator.setPosition(position);
         }
-        if (mAllowFancy) {
-            mAllPagesDelayedAnimator.setPosition(position);
-            if (mBrightnessAnimator != null) {
-                mBrightnessAnimator.setPosition(position);
+        for (int i = 0; i < mNonFirstPageQSAnimators.size(); i++) {
+            Pair<HeightExpansionAnimator, TouchAnimator> pair = mNonFirstPageQSAnimators.valueAt(i);
+            if (pair != null) {
+                pair.first.setPosition(position);
+                pair.second.setPosition(position);
             }
-            if (mQQSFooterActionsAnimator != null) {
-                mQQSFooterActionsAnimator.setPosition(position);
-            }
+        }
+        if (mQQSTileHeightAnimator != null) {
+            mQQSTileHeightAnimator.setPosition(position);
+        }
+        mQSTileLayoutTranslatorAnimator.setPosition(position);
+        mQQSTranslationYAnimator.setPosition(position);
+        mAllPagesDelayedAnimator.setPosition(position);
+        if (mBrightnessAnimator != null) {
+            mBrightnessAnimator.setPosition(position);
+        }
+        if (mQQSFooterActionsAnimator != null) {
+            mQQSFooterActionsAnimator.setPosition(position);
         }
     }
 
@@ -611,8 +742,11 @@
         if (mQQSTileHeightAnimator != null) {
             mQQSTileHeightAnimator.resetViewsHeights();
         }
-        if (mOtherTilesExpandAnimator != null) {
-            mOtherTilesExpandAnimator.resetViewsHeights();
+        if (mOtherFirstPageTilesHeightAnimator != null) {
+            mOtherFirstPageTilesHeightAnimator.resetViewsHeights();
+        }
+        for (int i = 0; i < mNonFirstPageQSAnimators.size(); i++) {
+            mNonFirstPageQSAnimators.valueAt(i).first.resetViewsHeights();
         }
         final int N2 = mAnimatedQsViews.size();
         for (int i = 0; i < N2; i++) {
@@ -623,7 +757,9 @@
     @Override
     public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
             int oldTop, int oldRight, int oldBottom) {
-        mExecutor.execute(mUpdateAnimators);
+        boolean actualChange =
+                left != oldLeft || top != oldTop || right != oldRight || bottom != oldBottom;
+        if (actualChange) mExecutor.execute(mUpdateAnimators);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index e82e9d2..bb8a1e8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -504,6 +504,12 @@
     }
 
     @Override
+    public int getHeightDiff() {
+        return mQSPanelScrollView.getBottom() - mHeader.getBottom()
+                + mHeader.getPaddingBottom();
+    }
+
+    @Override
     public void setQsExpansion(float expansion, float panelExpansionFraction,
             float proposedTranslation, float squishinessFraction) {
         float headerTranslation = mTransitioningToFullShade ? 0 : proposedTranslation;
@@ -537,8 +543,7 @@
 
         boolean fullyExpanded = expansion == 1;
         boolean fullyCollapsed = expansion == 0.0f;
-        int heightDiff = mQSPanelScrollView.getBottom() - mHeader.getBottom()
-                + mHeader.getPaddingBottom();
+        int heightDiff = getHeightDiff();
         float panelTranslationY = translationScaleY * heightDiff;
 
         // Let the views animate their contents correctly by giving them the necessary context.
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 20c0fdd..38061a8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -23,6 +23,7 @@
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
+import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
@@ -106,6 +107,7 @@
     protected QSTileLayout mTileLayout;
     private float mSquishinessFraction = 1f;
     private final ArrayMap<View, Integer> mChildrenLayoutTop = new ArrayMap<>();
+    private final Rect mClippingRect = new Rect();
 
     public QSPanel(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -133,8 +135,7 @@
 
             mHorizontalContentContainer = new RemeasuringLinearLayout(mContext);
             mHorizontalContentContainer.setOrientation(LinearLayout.VERTICAL);
-            mHorizontalContentContainer.setClipChildren(true);
-            mHorizontalContentContainer.setClipToPadding(false);
+            setHorizontalContentContainerClipping();
 
             LayoutParams lp = new LayoutParams(0, LayoutParams.WRAP_CONTENT, 1);
             int marginSize = (int) mContext.getResources().getDimension(R.dimen.qs_media_padding);
@@ -148,6 +149,23 @@
         }
     }
 
+    protected void setHorizontalContentContainerClipping() {
+        mHorizontalContentContainer.setClipChildren(true);
+        mHorizontalContentContainer.setClipToPadding(false);
+        // Don't clip on the top, that way, secondary pages tiles can animate up
+        mHorizontalContentContainer.addOnLayoutChangeListener(
+                (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
+                    if (left != oldLeft || right != oldRight || bottom != oldBottom) {
+                        mClippingRect.left = left;
+                        mClippingRect.right = right;
+                        mClippingRect.bottom = bottom;
+                        mHorizontalContentContainer.setClipBounds(mClippingRect);
+                    }
+                });
+        mClippingRect.top = -1000;
+        mHorizontalContentContainer.setClipBounds(mClippingRect);
+    }
+
     /**
      * Add brightness view above the tile layout.
      *
@@ -558,14 +576,6 @@
                     fireScanStateChanged(tileRecord.scanState);
                 }
             }
-
-            @Override
-            public void onAnnouncementRequested(CharSequence announcement) {
-                if (announcement != null) {
-                    mHandler.obtainMessage(H.ANNOUNCE_FOR_ACCESSIBILITY, announcement)
-                            .sendToTarget();
-                }
-            }
         };
 
         tileRecord.tile.addCallback(callback);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
index d470fa2..ff9790c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
@@ -45,6 +45,7 @@
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Objects;
 import java.util.function.Consumer;
 import java.util.stream.Collectors;
 
@@ -258,6 +259,15 @@
         return null;
     }
 
+    QSTileView getTileView(String spec) {
+        for (QSPanelControllerBase.TileRecord r : mRecords) {
+            if (Objects.equals(r.tile.getTileSpec(), spec)) {
+                return r.tileView;
+            }
+        }
+        return null;
+    }
+
     private String getTilesSpecs() {
         return mRecords.stream()
                 .map(tileRecord ->  tileRecord.tile.getTileSpec())
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index 613e7f8..f5ae019 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -46,11 +46,9 @@
     }
 
     @Override
-    void initialize() {
-        super.initialize();
-        if (mHorizontalContentContainer != null) {
-            mHorizontalContentContainer.setClipChildren(false);
-        }
+    protected void setHorizontalContentContainerClipping() {
+        mHorizontalContentContainer.setClipToPadding(false);
+        mHorizontalContentContainer.setClipChildren(false);
     }
 
     @Override
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 d4350f1..eae2565 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
@@ -212,9 +212,6 @@
 
         @Override
         public void onScanStateChanged(boolean state) {}
-
-        @Override
-        public void onAnnouncementRequested(CharSequence announcement) {}
     }
 
     private void addPackageTiles(final QSTileHost host) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
index c2a9e3a..76950d1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
@@ -32,6 +32,7 @@
 import com.android.systemui.qs.tiles.CameraToggleTile;
 import com.android.systemui.qs.tiles.CastTile;
 import com.android.systemui.qs.tiles.CellularTile;
+import com.android.systemui.qs.tiles.ColorCorrectionTile;
 import com.android.systemui.qs.tiles.ColorInversionTile;
 import com.android.systemui.qs.tiles.DataSaverTile;
 import com.android.systemui.qs.tiles.DeviceControlsTile;
@@ -71,6 +72,7 @@
     private final Provider<BluetoothTile> mBluetoothTileProvider;
     private final Provider<CellularTile> mCellularTileProvider;
     private final Provider<DndTile> mDndTileProvider;
+    private final Provider<ColorCorrectionTile> mColorCorrectionTileProvider;
     private final Provider<ColorInversionTile> mColorInversionTileProvider;
     private final Provider<AirplaneModeTile> mAirplaneModeTileProvider;
     private final Provider<WorkModeTile> mWorkModeTileProvider;
@@ -133,7 +135,8 @@
             Provider<QuickAccessWalletTile> quickAccessWalletTileProvider,
             Provider<QRCodeScannerTile> qrCodeScannerTileProvider,
             Provider<OneHandedModeTile> oneHandedModeTileProvider,
-            Provider<FgsManagerTile> fgsManagerTileProvider) {
+            Provider<FgsManagerTile> fgsManagerTileProvider,
+            Provider<ColorCorrectionTile> colorCorrectionTileProvider) {
         mQsHostLazy = qsHostLazy;
         mCustomTileBuilderProvider = customTileBuilderProvider;
 
@@ -167,6 +170,7 @@
         mQRCodeScannerTileProvider = qrCodeScannerTileProvider;
         mOneHandedModeTileProvider = oneHandedModeTileProvider;
         mFgsManagerTileProvider = fgsManagerTileProvider;
+        mColorCorrectionTileProvider = colorCorrectionTileProvider;
     }
 
     public final QSTile createTile(String tileSpec) {
@@ -239,6 +243,8 @@
                 return mOneHandedModeTileProvider.get();
             case "fgsmanager":
                 return mFgsManagerTileProvider.get();
+            case "color_correction":
+                return mColorCorrectionTileProvider.get();
         }
 
         // Custom tiles
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 70e3a2b..b5f07d1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
@@ -156,8 +156,14 @@
      *
      * Categories are defined in {@link com.android.internal.logging.nano.MetricsProto.MetricsEvent}
      * by editing frameworks/base/proto/src/metrics_constants.proto.
+     *
+     * @deprecated Not needed as this logging is deprecated. Logging tiles is done using
+     * {@link QSTile#getMetricsSpec}
      */
-    abstract public int getMetricsCategory();
+    @Deprecated
+    public int getMetricsCategory() {
+        return 0;
+    }
 
     /**
      * Performs initialization of the tile
@@ -445,27 +451,11 @@
     }
 
     private void handleStateChanged() {
-        boolean delayAnnouncement = shouldAnnouncementBeDelayed();
         if (mCallbacks.size() != 0) {
             for (int i = 0; i < mCallbacks.size(); i++) {
                 mCallbacks.get(i).onStateChanged(mState);
             }
-            if (mAnnounceNextStateChange && !delayAnnouncement) {
-                String announcement = composeChangeAnnouncement();
-                if (announcement != null) {
-                    mCallbacks.get(0).onAnnouncementRequested(announcement);
-                }
-            }
         }
-        mAnnounceNextStateChange = mAnnounceNextStateChange && delayAnnouncement;
-    }
-
-    protected boolean shouldAnnouncementBeDelayed() {
-        return false;
-    }
-
-    protected String composeChangeAnnouncement() {
-        return null;
     }
 
     private void handleShowDetail(boolean show) {
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 6bb79867..7efb983 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
@@ -653,7 +653,8 @@
         "qr_code_scanner" to R.array.tile_states_qr_code_scanner,
         "alarm" to R.array.tile_states_alarm,
         "onehanded" to R.array.tile_states_onehanded,
-        "fgsmanager" to R.array.tile_states_fgsmanager
+        "fgsmanager" to R.array.tile_states_fgsmanager,
+        "color_correction" to R.array.tile_states_color_correction
     )
 
     fun getSubtitleId(spec: String?): Int {
@@ -665,4 +666,4 @@
     return PropertyValuesHolder.ofInt(name, *values).apply {
         setEvaluator(ArgbEvaluator.getInstance())
     }
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
index 5650a17..ccec80d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
@@ -144,15 +144,6 @@
         return MetricsEvent.QS_AIRPLANEMODE;
     }
 
-    @Override
-    protected String composeChangeAnnouncement() {
-        if (mState.value) {
-            return mContext.getString(R.string.accessibility_quick_settings_airplane_changed_on);
-        } else {
-            return mContext.getString(R.string.accessibility_quick_settings_airplane_changed_off);
-        }
-    }
-
     public void handleSetListening(boolean listening) {
         super.handleSetListening(listening);
         if (mListening == listening) return;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index 6fcfc3a..5552105 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -243,15 +243,6 @@
     }
 
     @Override
-    protected String composeChangeAnnouncement() {
-        if (mState.value) {
-            return mContext.getString(R.string.accessibility_quick_settings_bluetooth_changed_on);
-        } else {
-            return mContext.getString(R.string.accessibility_quick_settings_bluetooth_changed_off);
-        }
-    }
-
-    @Override
     public boolean isAvailable() {
         return mController.isBluetoothSupported();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
index 6e0ae29..76c84f9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -287,15 +287,6 @@
         return MetricsEvent.QS_CAST;
     }
 
-    @Override
-    protected String composeChangeAnnouncement() {
-        if (!mState.value) {
-            // We only announce when it's turned off to avoid vocal overflow.
-            return mContext.getString(R.string.accessibility_casting_turned_off);
-        }
-        return null;
-    }
-
     private String getDeviceName(CastDevice device) {
         return device.name != null ? device.name
                 : mContext.getString(R.string.quick_settings_cast_device_default_name);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorCorrectionTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorCorrectionTile.java
new file mode 100644
index 0000000..6dfcf5c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorCorrectionTile.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.tiles;
+
+import android.content.Intent;
+import android.os.Handler;
+import android.os.Looper;
+import android.provider.Settings;
+import android.provider.Settings.Secure;
+import android.service.quicksettings.Tile;
+import android.view.View;
+import android.widget.Switch;
+
+import androidx.annotation.Nullable;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.systemui.R;
+import com.android.systemui.R.drawable;
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.plugins.qs.QSTile.BooleanState;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.qs.QSHost;
+import com.android.systemui.qs.SettingObserver;
+import com.android.systemui.qs.logging.QSLogger;
+import com.android.systemui.qs.tileimpl.QSTileImpl;
+import com.android.systemui.settings.UserTracker;
+import com.android.systemui.util.settings.SecureSettings;
+
+import javax.inject.Inject;
+
+/** Quick settings tile: Color correction **/
+public class ColorCorrectionTile extends QSTileImpl<BooleanState> {
+
+    private final Icon mIcon = ResourceIcon.get(drawable.ic_qs_color_correction);
+    private final SettingObserver mSetting;
+
+    @Inject
+    public ColorCorrectionTile(
+            QSHost host,
+            @Background Looper backgroundLooper,
+            @Main Handler mainHandler,
+            FalsingManager falsingManager,
+            MetricsLogger metricsLogger,
+            StatusBarStateController statusBarStateController,
+            ActivityStarter activityStarter,
+            QSLogger qsLogger,
+            UserTracker userTracker,
+            SecureSettings secureSettings
+    ) {
+        super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
+                statusBarStateController, activityStarter, qsLogger);
+
+        mSetting = new SettingObserver(secureSettings, mHandler,
+                Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, userTracker.getUserId()) {
+            @Override
+            protected void handleValueChanged(int value, boolean observedChange) {
+                // mHandler is the background handler so calling this is OK
+                handleRefreshState(value);
+            }
+        };
+    }
+
+    @Override
+    protected void handleDestroy() {
+        super.handleDestroy();
+        mSetting.setListening(false);
+    }
+
+    @Override
+    public BooleanState newTileState() {
+        return new BooleanState();
+    }
+
+    @Override
+    public void handleSetListening(boolean listening) {
+        super.handleSetListening(listening);
+        mSetting.setListening(listening);
+    }
+
+    @Override
+    protected void handleUserSwitch(int newUserId) {
+        mSetting.setUserId(newUserId);
+        handleRefreshState(mSetting.getValue());
+    }
+
+    @Override
+    public Intent getLongClickIntent() {
+        return new Intent(Settings.ACTION_COLOR_CORRECTION_SETTINGS);
+    }
+
+    @Override
+    protected void handleClick(@Nullable View view) {
+        mSetting.setValue(mState.value ? 0 : 1);
+    }
+
+    @Override
+    public CharSequence getTileLabel() {
+        return mContext.getString(R.string.quick_settings_color_correction_label);
+    }
+
+    @Override
+    protected void handleUpdateState(BooleanState state, Object arg) {
+        final int value = arg instanceof Integer ? (Integer) arg : mSetting.getValue();
+        final boolean enabled = value != 0;
+        state.value = enabled;
+        state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
+        state.label = mContext.getString(R.string.quick_settings_color_correction_label);
+        state.icon = mIcon;
+        state.expandedAccessibilityClassName = Switch.class.getName();
+        state.contentDescription = state.label;
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        // MetricsProto/MetricsEvent is deprecated, so just simply return 0 here.
+        return 0;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
index d2d2180..c2a82a7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
@@ -49,15 +49,9 @@
 /** Quick settings tile: Invert colors **/
 public class ColorInversionTile extends QSTileImpl<BooleanState> {
 
-    private static final String EXTRA_FRAGMENT_ARGS_KEY = ":settings:fragment_args_key";
-    private static final String EXTRA_SHOW_FRAGMENT_ARGS_KEY = ":settings:show_fragment_args";
-    private static final String COLOR_INVERSION_PREFERENCE_KEY = "toggle_inversion_preference";
-
     private final Icon mIcon = ResourceIcon.get(drawable.ic_invert_colors);
     private final SettingObserver mSetting;
 
-    private boolean mListening;
-
     @Inject
     public ColorInversionTile(
             QSHost host,
@@ -126,11 +120,7 @@
     protected void handleUpdateState(BooleanState state, Object arg) {
         final int value = arg instanceof Integer ? (Integer) arg : mSetting.getValue();
         final boolean enabled = value != 0;
-        if (state.slash == null) {
-            state.slash = new SlashState();
-        }
         state.value = enabled;
-        state.slash.isSlashed = !state.value;
         state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
         state.label = mContext.getString(R.string.quick_settings_inversion_label);
         state.icon = mIcon;
@@ -142,15 +132,4 @@
     public int getMetricsCategory() {
         return MetricsEvent.QS_COLORINVERSION;
     }
-
-    @Override
-    protected String composeChangeAnnouncement() {
-        if (mState.value) {
-            return mContext.getString(
-                    R.string.accessibility_quick_settings_color_inversion_changed_on);
-        } else {
-            return mContext.getString(
-                    R.string.accessibility_quick_settings_color_inversion_changed_off);
-        }
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
index a2577d6..1bbe411 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
@@ -138,15 +138,6 @@
     }
 
     @Override
-    protected String composeChangeAnnouncement() {
-        if (mState.value) {
-            return mContext.getString(R.string.accessibility_quick_settings_data_saver_changed_on);
-        } else {
-            return mContext.getString(R.string.accessibility_quick_settings_data_saver_changed_off);
-        }
-    }
-
-    @Override
     public void onDataSaverChanged(boolean isDataSaving) {
         refreshState(isDataSaving);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
index bb27458..49c548d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -307,15 +307,6 @@
     }
 
     @Override
-    protected String composeChangeAnnouncement() {
-        if (mState.value) {
-            return mContext.getString(R.string.accessibility_quick_settings_dnd_changed_on);
-        } else {
-            return mContext.getString(R.string.accessibility_quick_settings_dnd_changed_off);
-        }
-    }
-
-    @Override
     public void handleSetListening(boolean listening) {
         super.handleSetListening(listening);
         if (mListening == listening) return;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
index c0065a0..73b0896 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
@@ -153,15 +153,6 @@
     }
 
     @Override
-    protected String composeChangeAnnouncement() {
-        if (mState.value) {
-            return mContext.getString(R.string.accessibility_quick_settings_flashlight_changed_on);
-        } else {
-            return mContext.getString(R.string.accessibility_quick_settings_flashlight_changed_off);
-        }
-    }
-
-    @Override
     public void onFlashlightChanged(boolean enabled) {
         refreshState(enabled);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
index 87edc2c..d7aa8b2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
@@ -195,15 +195,6 @@
         return MetricsEvent.QS_HOTSPOT;
     }
 
-    @Override
-    protected String composeChangeAnnouncement() {
-        if (mState.value) {
-            return mContext.getString(R.string.accessibility_quick_settings_hotspot_changed_on);
-        } else {
-            return mContext.getString(R.string.accessibility_quick_settings_hotspot_changed_off);
-        }
-    }
-
     /**
      * Listens to changes made to hotspot and data saver states (to toggle tile availability).
      */
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
index 6a018f6..fc93f44 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
@@ -132,15 +132,6 @@
         return MetricsEvent.QS_LOCATION;
     }
 
-    @Override
-    protected String composeChangeAnnouncement() {
-        if (mState.value) {
-            return mContext.getString(R.string.accessibility_quick_settings_location_changed_on);
-        } else {
-            return mContext.getString(R.string.accessibility_quick_settings_location_changed_off);
-        }
-    }
-
     private final class Callback implements LocationChangeCallback,
             KeyguardStateController.Callback {
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java
index cd2e27a..0886b46 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java
@@ -147,15 +147,6 @@
         return MetricsEvent.QS_NFC;
     }
 
-    @Override
-    protected String composeChangeAnnouncement() {
-        if (mState.value) {
-            return mContext.getString(R.string.quick_settings_nfc_on);
-        } else {
-            return mContext.getString(R.string.quick_settings_nfc_off);
-        }
-    }
-
     private NfcAdapter getAdapter() {
         if (mAdapter == null) {
             try {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
index 0bbb5bd..177c82e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
@@ -16,12 +16,18 @@
 
 package com.android.systemui.qs.tiles;
 
+import static android.hardware.SensorPrivacyManager.Sensors.CAMERA;
+
+import static com.android.systemui.statusbar.policy.RotationLockControllerImpl.hasSufficientPermission;
+
 import android.content.Intent;
 import android.content.res.Configuration;
 import android.content.res.Resources;
+import android.hardware.SensorPrivacyManager;
 import android.os.Handler;
 import android.os.Looper;
 import android.provider.Settings;
+import android.provider.Settings.Secure;
 import android.service.quicksettings.Tile;
 import android.view.View;
 import android.widget.Switch;
@@ -38,18 +44,25 @@
 import com.android.systemui.plugins.qs.QSTile.BooleanState;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSHost;
+import com.android.systemui.qs.SettingObserver;
 import com.android.systemui.qs.logging.QSLogger;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
+import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.RotationLockController;
 import com.android.systemui.statusbar.policy.RotationLockController.RotationLockControllerCallback;
+import com.android.systemui.util.settings.SecureSettings;
 
 import javax.inject.Inject;
 
 /** Quick settings tile: Rotation **/
-public class RotationLockTile extends QSTileImpl<BooleanState> {
+public class RotationLockTile extends QSTileImpl<BooleanState> implements
+        BatteryController.BatteryStateChangeCallback {
 
     private final Icon mIcon = ResourceIcon.get(com.android.internal.R.drawable.ic_qs_auto_rotate);
     private final RotationLockController mController;
+    private final SensorPrivacyManager mPrivacyManager;
+    private final BatteryController mBatteryController;
+    private final SettingObserver mSetting;
 
     @Inject
     public RotationLockTile(
@@ -61,12 +74,41 @@
             StatusBarStateController statusBarStateController,
             ActivityStarter activityStarter,
             QSLogger qsLogger,
-            RotationLockController rotationLockController
+            RotationLockController rotationLockController,
+            SensorPrivacyManager privacyManager,
+            BatteryController batteryController,
+            SecureSettings secureSettings
     ) {
         super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
                 statusBarStateController, activityStarter, qsLogger);
         mController = rotationLockController;
         mController.observe(this, mCallback);
+        mPrivacyManager = privacyManager;
+        mBatteryController = batteryController;
+        int currentUser = host.getUserContext().getUserId();
+        mSetting = new SettingObserver(
+                secureSettings,
+                mHandler,
+                Secure.CAMERA_AUTOROTATE,
+                currentUser
+        ) {
+            @Override
+            protected void handleValueChanged(int value, boolean observedChange) {
+                // mHandler is the background handler so calling this is OK
+                handleRefreshState(null);
+            }
+        };
+        mBatteryController.observe(getLifecycle(), this);
+    }
+
+    @Override
+    protected void handleInitialize() {
+        mPrivacyManager.addSensorPrivacyListener(CAMERA, mSensorPrivacyChangedListener);
+    }
+
+    @Override
+    public void onPowerSaveChanged(boolean isPowerSave) {
+        refreshState();
     }
 
     @Override
@@ -95,14 +137,46 @@
     protected void handleUpdateState(BooleanState state, Object arg) {
         final boolean rotationLocked = mController.isRotationLocked();
 
+        final boolean powerSave = mBatteryController.isPowerSave();
+        final boolean cameraLocked = mPrivacyManager.isSensorPrivacyEnabled(CAMERA);
+        final boolean cameraRotation =
+                !powerSave && !cameraLocked && hasSufficientPermission(mContext)
+                        && mController.isCameraRotationEnabled();
         state.value = !rotationLocked;
         state.label = mContext.getString(R.string.quick_settings_rotation_unlocked_label);
         state.icon = mIcon;
         state.contentDescription = getAccessibilityString(rotationLocked);
+        if (!rotationLocked && cameraRotation) {
+            state.secondaryLabel = mContext.getResources().getString(
+                    R.string.rotation_lock_camera_rotation_on);
+        } else {
+            state.secondaryLabel = "";
+        }
+        state.stateDescription = state.secondaryLabel;
+
         state.expandedAccessibilityClassName = Switch.class.getName();
         state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
     }
 
+    @Override
+    protected void handleDestroy() {
+        super.handleDestroy();
+        mSetting.setListening(false);
+        mPrivacyManager.removeSensorPrivacyListener(CAMERA, mSensorPrivacyChangedListener);
+    }
+
+    @Override
+    public void handleSetListening(boolean listening) {
+        super.handleSetListening(listening);
+        mSetting.setListening(listening);
+    }
+
+    @Override
+    protected void handleUserSwitch(int newUserId) {
+        mSetting.setUserId(newUserId);
+        handleRefreshState(null);
+    }
+
     public static boolean isCurrentOrientationLockPortrait(RotationLockController controller,
             Resources resources) {
         int lockOrientation = controller.getRotationLockOrientation();
@@ -129,15 +203,14 @@
         return mContext.getString(R.string.accessibility_quick_settings_rotation);
     }
 
-    @Override
-    protected String composeChangeAnnouncement() {
-        return getAccessibilityString(mState.value);
-    }
-
     private final RotationLockControllerCallback mCallback = new RotationLockControllerCallback() {
         @Override
         public void onRotationLockStateChanged(boolean rotationLocked, boolean affordanceVisible) {
             refreshState(rotationLocked);
         }
     };
+
+    private final SensorPrivacyManager.OnSensorPrivacyChangedListener
+            mSensorPrivacyChangedListener =
+            (sensor, enabled) -> refreshState();
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
index da0069f..1608248 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -254,20 +254,6 @@
     }
 
     @Override
-    protected boolean shouldAnnouncementBeDelayed() {
-        return mStateBeforeClick.value == mState.value;
-    }
-
-    @Override
-    protected String composeChangeAnnouncement() {
-        if (mState.value) {
-            return mContext.getString(R.string.accessibility_quick_settings_wifi_changed_on);
-        } else {
-            return mContext.getString(R.string.accessibility_quick_settings_wifi_changed_off);
-        }
-    }
-
-    @Override
     public boolean isAvailable() {
         return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI);
     }
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 c9c1a9b..a22fda7 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessDialog.java
@@ -93,6 +93,12 @@
     }
 
     @Override
+    protected void onPause() {
+        super.onPause();
+        overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
+    }
+
+    @Override
     protected void onStop() {
         super.onStop();
         MetricsLogger.hidden(this, MetricsEvent.BRIGHTNESS_DIALOG);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java
index 43b3fb1..7cf0583 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java
@@ -257,6 +257,30 @@
         return !canRemoveImmediately(entry.getKey());
     }
 
+    /**
+     * @param key
+     * @return true if the entry is pinned
+     */
+    public boolean isSticky(String key) {
+        AlertEntry alerting = mAlertEntries.get(key);
+        if (alerting != null) {
+            return alerting.isSticky();
+        }
+        return false;
+    }
+
+    /**
+     * @param key
+     * @return When a HUN entry should be removed in milliseconds from now
+     */
+    public long getEarliestRemovalTime(String key) {
+        AlertEntry alerting = mAlertEntries.get(key);
+        if (alerting != null) {
+            return Math.max(0, alerting.mEarliestRemovaltime - mClock.currentTimeMillis());
+        }
+        return 0;
+    }
+
     @Override
     public void setShouldManageLifetime(NotificationEntry entry, boolean shouldExtend) {
         if (shouldExtend) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index d7b4738..8ce73d7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -31,6 +31,7 @@
 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_RESTING;
 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_TRUST;
 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_USER_LOCKED;
+import static com.android.systemui.keyguard.ScreenLifecycle.SCREEN_ON;
 import static com.android.systemui.plugins.FalsingManager.LOW_PENALTY;
 
 import android.animation.Animator;
@@ -78,6 +79,7 @@
 import com.android.systemui.dock.DockManager;
 import com.android.systemui.keyguard.KeyguardIndication;
 import com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController;
+import com.android.systemui.keyguard.ScreenLifecycle;
 import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
@@ -172,6 +174,18 @@
                     return view == mIndicationArea;
                 }
             };
+    private ScreenLifecycle mScreenLifecycle;
+    private final ScreenLifecycle.Observer mScreenObserver = new ScreenLifecycle.Observer() {
+        @Override
+        public void onScreenTurnedOn() {
+            if (mMessageToShowOnScreenOn != null) {
+                showBiometricMessage(mMessageToShowOnScreenOn);
+                // We want to keep this message around in case the screen was off
+                hideBiometricMessageDelayed(BaseKeyguardCallback.HIDE_DELAY_MS);
+                mMessageToShowOnScreenOn = null;
+            }
+        }
+    };
 
     /**
      * Creates a new KeyguardIndicationController and registers callbacks.
@@ -190,6 +204,7 @@
             @Main DelayableExecutor executor,
             FalsingManager falsingManager,
             LockPatternUtils lockPatternUtils,
+            ScreenLifecycle screenLifecycle,
             IActivityManager iActivityManager,
             KeyguardBypassController keyguardBypassController) {
         mContext = context;
@@ -208,7 +223,8 @@
         mIActivityManager = iActivityManager;
         mFalsingManager = falsingManager;
         mKeyguardBypassController = keyguardBypassController;
-
+        mScreenLifecycle = screenLifecycle;
+        mScreenLifecycle.addObserver(mScreenObserver);
     }
 
     /** Call this after construction to finish setting up the instance. */
@@ -991,7 +1007,7 @@
             if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
                 mStatusBarKeyguardViewManager.showBouncerMessage(helpString,
                         mInitialTextColorState);
-            } else if (mKeyguardUpdateMonitor.isScreenOn()) {
+            } else if (mScreenLifecycle.getScreenState() == SCREEN_ON) {
                 if (biometricSourceType == BiometricSourceType.FACE
                         && shouldSuppressFaceMsgAndShowTryFingerprintMsg()) {
                     showTryFingerprintMsg(msgId, helpString);
@@ -1013,7 +1029,7 @@
             if (biometricSourceType == BiometricSourceType.FACE
                     && shouldSuppressFaceMsgAndShowTryFingerprintMsg()
                     && !mStatusBarKeyguardViewManager.isBouncerShowing()
-                    && mKeyguardUpdateMonitor.isScreenOn()) {
+                    && mScreenLifecycle.getScreenState() == SCREEN_ON) {
                 showTryFingerprintMsg(msgId, errString);
                 return;
             }
@@ -1035,7 +1051,7 @@
                 }
             } else if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
                 mStatusBarKeyguardViewManager.showBouncerMessage(errString, mInitialTextColorState);
-            } else if (mKeyguardUpdateMonitor.isScreenOn()) {
+            } else if (mScreenLifecycle.getScreenState() == SCREEN_ON) {
                 showBiometricMessage(errString);
             } else {
                 mMessageToShowOnScreenOn = errString;
@@ -1086,16 +1102,6 @@
         }
 
         @Override
-        public void onScreenTurnedOn() {
-            if (mMessageToShowOnScreenOn != null) {
-                showBiometricMessage(mMessageToShowOnScreenOn);
-                // We want to keep this message around in case the screen was off
-                hideBiometricMessageDelayed(HIDE_DELAY_MS);
-                mMessageToShowOnScreenOn = null;
-            }
-        }
-
-        @Override
         public void onBiometricRunningStateChanged(boolean running,
                 BiometricSourceType biometricSourceType) {
             if (running && biometricSourceType == BiometricSourceType.FACE) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
index 03d8e7e..c8115e2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
@@ -92,6 +92,8 @@
     override fun setRevealAmountOnScrim(amount: Float, scrim: LightRevealScrim) {
         val interpolatedAmount = INTERPOLATOR.getInterpolation(amount)
 
+        scrim.interpolatedRevealAmount = interpolatedAmount
+
         scrim.startColorAlpha =
             getPercentPastThreshold(1 - interpolatedAmount,
                 threshold = 1 - START_COLOR_REVEAL_PERCENTAGE)
@@ -152,6 +154,7 @@
         // non-interpolated amount
         val fadeAmount = getPercentPastThreshold(amount, 0.5f)
         val radius = startRadius + ((endRadius - startRadius) * amount)
+        scrim.interpolatedRevealAmount = amount
         scrim.revealGradientEndColorAlpha = 1f - fadeAmount
         scrim.setRevealGradientBounds(
             centerX - radius /* left */,
@@ -182,6 +185,7 @@
 
         with(scrim) {
             revealGradientEndColorAlpha = 1f - fadeAmount
+            interpolatedRevealAmount = interpolatedAmount
             setRevealGradientBounds(
                     width * (1f + OFF_SCREEN_START_AMOUNT) -
                             width * WIDTH_INCREASE_MULTIPLIER * interpolatedAmount,
@@ -284,6 +288,14 @@
             }
         }
 
+    var interpolatedRevealAmount: Float = 1f
+
+    val isScrimAlmostOccludes: Boolean
+        get() {
+            // if the interpolatedRevealAmount less than 0.1, over 90% of the screen is black.
+            return interpolatedRevealAmount < 0.1f
+        }
+
     private fun updateScrimOpaque() {
         isScrimOpaque = revealAmount == 0.0f && alpha == 1.0f && visibility == VISIBLE
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index 210ee96..3730d12 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -379,6 +379,7 @@
         }
     }
 
+    @Nullable
     public String getMediaNotificationKey() {
         return mMediaNotificationKey;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
index 2dbe59e..bd948ece 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
@@ -28,6 +28,7 @@
 import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
 import android.os.SystemProperties;
+import android.os.Trace;
 import android.text.format.DateFormat;
 import android.util.FloatProperty;
 import android.util.Log;
@@ -193,6 +194,7 @@
             mState = state;
             mUpcomingState = state;
             mUiEventLogger.log(StatusBarStateEvent.fromState(mState));
+            Trace.instantForTrack(Trace.TRACE_TAG_APP, "UI Events", "StatusBarState " + tag);
             for (RankedListener rl : new ArrayList<>(mListeners)) {
                 rl.mListener.onStateChanged(mState);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/charging/DwellRippleShader.kt b/packages/SystemUI/src/com/android/systemui/statusbar/charging/DwellRippleShader.kt
index a1d086b..73d3e2a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/charging/DwellRippleShader.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/charging/DwellRippleShader.kt
@@ -59,8 +59,8 @@
                 }
 
                 vec2 distort(vec2 p, float time, float distort_amount_xy, float frequency) {
-                    return p + vec2(sin(p.x * frequency + in_phase1),
-                                    cos(p.y * frequency * 1.23 + in_phase2)) * distort_amount_xy;
+                    return p + vec2(sin(p.y * frequency + in_phase1),
+                                    cos(p.x * frequency * -1.23 + in_phase2)) * distort_amount_xy;
                 }
 
                 vec4 ripple(vec2 p, float distort_xy, float frequency) {
@@ -73,11 +73,11 @@
                 """
         private const val SHADER_MAIN = """vec4 main(vec2 p) {
                     vec4 color1 = ripple(p,
-                        12 * in_distortion_strength, // distort_xy
+                        34 * in_distortion_strength, // distort_xy
                         0.012 // frequency
                     );
                     vec4 color2 = ripple(p,
-                        17.5 * in_distortion_strength, // distort_xy
+                        49 * in_distortion_strength, // distort_xy
                         0.018 // frequency
                     );
                     // Alpha blend between two layers.
@@ -128,8 +128,8 @@
         set(value) {
             field = value * 0.001f
             setUniform("in_time", field)
-            setUniform("in_phase1", field * 2f + 0.367f)
-            setUniform("in_phase2", field * 5.2f * 1.531f)
+            setUniform("in_phase1", field * 3f + 0.367f)
+            setUniform("in_phase2", field * 7.2f * 1.531f)
         }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
index f500d39..4717b3a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
@@ -20,8 +20,6 @@
 import static com.android.systemui.statusbar.notification.collection.NotifCollection.REASON_UNKNOWN;
 import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationCallback;
 
-import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.app.Notification;
 import android.os.RemoteException;
 import android.os.SystemClock;
@@ -33,6 +31,9 @@
 import android.util.ArraySet;
 import android.util.Log;
 
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.statusbar.NotificationVisibility;
@@ -123,8 +124,8 @@
      * filtered out if for instance they are not for the current user
      */
     private final ArrayMap<String, NotificationEntry> mActiveNotifications = new ArrayMap<>();
-    @VisibleForTesting
     /** This is the list of "active notifications for this user in this context" */
+    @VisibleForTesting
     protected final ArrayList<NotificationEntry> mSortedAndFiltered = new ArrayList<>();
     private final List<NotificationEntry> mReadOnlyNotifications =
             Collections.unmodifiableList(mSortedAndFiltered);
@@ -899,7 +900,7 @@
     }
 
     /** Calls to NotificationRankingManager and updates mSortedAndFiltered */
-    private void updateRankingAndSort(@NonNull RankingMap rankingMap, String reason) {
+    private void updateRankingAndSort(RankingMap rankingMap, String reason) {
         if (mNotifPipelineFlags.isNewPipelineEnabled()) {
             mLogger.logUseWhileNewPipelineActive("updateRankingAndSort", reason);
             return;
@@ -961,6 +962,7 @@
      * Returns a collections containing ALL notifications we know about, including ones that are
      * hidden or for other users. See {@link CommonNotifCollection#getAllNotifs()}.
      */
+    @NonNull
     @Override
     public Collection<NotificationEntry> getAllNotifs() {
         mNotifPipelineFlags.checkLegacyPipelineEnabled();
@@ -969,7 +971,7 @@
 
     @Nullable
     @Override
-    public NotificationEntry getEntry(String key) {
+    public NotificationEntry getEntry(@NonNull String key) {
         mNotifPipelineFlags.checkLegacyPipelineEnabled();
         return getPendingOrActiveNotif(key);
     }
@@ -989,7 +991,7 @@
     }
 
     @Override
-    public void addCollectionListener(NotifCollectionListener listener) {
+    public void addCollectionListener(@NonNull NotifCollectionListener listener) {
         mNotifCollectionListeners.add(listener);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt
index 22c3eda..9da7d21 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt
@@ -16,7 +16,8 @@
 class NotificationLaunchAnimatorControllerProvider(
     private val notificationShadeWindowViewController: NotificationShadeWindowViewController,
     private val notificationListContainer: NotificationListContainer,
-    private val headsUpManager: HeadsUpManagerPhone
+    private val headsUpManager: HeadsUpManagerPhone,
+    private val jankMonitor: InteractionJankMonitor
 ) {
     fun getAnimatorController(
         notification: ExpandableNotificationRow
@@ -25,7 +26,8 @@
             notificationShadeWindowViewController,
             notificationListContainer,
             headsUpManager,
-            notification
+            notification,
+            jankMonitor
         )
     }
 }
@@ -39,7 +41,8 @@
     private val notificationShadeWindowViewController: NotificationShadeWindowViewController,
     private val notificationListContainer: NotificationListContainer,
     private val headsUpManager: HeadsUpManagerPhone,
-    private val notification: ExpandableNotificationRow
+    private val notification: ExpandableNotificationRow,
+    private val jankMonitor: InteractionJankMonitor
 ) : ActivityLaunchAnimator.Controller {
 
     companion object {
@@ -137,12 +140,12 @@
         notification.isExpandAnimationRunning = true
         notificationListContainer.setExpandingNotification(notification)
 
-        InteractionJankMonitor.getInstance().begin(notification,
+        jankMonitor.begin(notification,
             InteractionJankMonitor.CUJ_NOTIFICATION_APP_START)
     }
 
     override fun onLaunchAnimationEnd(isExpandingFullyAbove: Boolean) {
-        InteractionJankMonitor.getInstance().end(InteractionJankMonitor.CUJ_NOTIFICATION_APP_START)
+        jankMonitor.end(InteractionJankMonitor.CUJ_NOTIFICATION_APP_START)
 
         notification.isExpandAnimationRunning = false
         notificationShadeWindowViewController.setExpandAnimationRunning(false)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
index f8f1279..b6b9c3f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
@@ -44,7 +44,6 @@
 
 import android.annotation.IntDef;
 import android.annotation.MainThread;
-import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.app.Notification;
 import android.os.Handler;
@@ -59,6 +58,7 @@
 import android.util.Pair;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.systemui.Dumpable;
@@ -193,7 +193,8 @@
     }
 
     /** @see NotifPipeline#getEntry(String) () */
-    NotificationEntry getEntry(String key) {
+    @Nullable
+    NotificationEntry getEntry(@NonNull String key) {
         return mNotificationSet.get(key);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java
index e9b7caa5..85c0064 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java
@@ -82,11 +82,8 @@
     public void attach(NotifPipeline pipeline) {
         mNotifPipeline = pipeline;
         mNotifPipeline.addNotificationDismissInterceptor(mDismissInterceptor);
-        mNotifPipeline.addFinalizeFilter(mNotifFilter);
-        if (mBubblesManagerOptional.isPresent()) {
-            mBubblesManagerOptional.get().addNotifCallback(mNotifCallback);
-        }
-
+        mNotifPipeline.addPreGroupFilter(mNotifFilter);
+        mBubblesManagerOptional.ifPresent(manager -> manager.addNotifCallback(mNotifCallback));
     }
 
     private final NotifFilter mNotifFilter = new NotifFilter(TAG) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java
index f8b4274..ed9663e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java
@@ -19,9 +19,12 @@
 import static com.android.systemui.statusbar.NotificationRemoteInputManager.FORCE_REMOTE_INPUT_HISTORY;
 import static com.android.systemui.statusbar.notification.interruption.HeadsUpController.alertAgain;
 
+import android.util.ArraySet;
+
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.notification.collection.ListEntry;
 import com.android.systemui.statusbar.notification.collection.NotifPipeline;
@@ -38,8 +41,7 @@
 import com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
-
-import java.util.Objects;
+import com.android.systemui.util.concurrency.DelayableExecutor;
 
 import javax.inject.Inject;
 
@@ -66,12 +68,11 @@
     private final NotificationInterruptStateProvider mNotificationInterruptStateProvider;
     private final NotificationRemoteInputManager mRemoteInputManager;
     private final NodeController mIncomingHeaderController;
-
-    // tracks the current HeadUpNotification reported by HeadsUpManager
-    private @Nullable NotificationEntry mCurrentHun;
+    private final DelayableExecutor mExecutor;
 
     private NotifLifetimeExtender.OnEndLifetimeExtensionCallback mEndLifetimeExtension;
-    private NotificationEntry mNotifExtendingLifetime; // notif we've extended the lifetime for
+    // notifs we've extended the lifetime for
+    private final ArraySet<NotificationEntry> mNotifsExtendingLifetime = new ArraySet<>();
 
     @Inject
     public HeadsUpCoordinator(
@@ -79,12 +80,14 @@
             HeadsUpViewBinder headsUpViewBinder,
             NotificationInterruptStateProvider notificationInterruptStateProvider,
             NotificationRemoteInputManager remoteInputManager,
-            @IncomingHeader NodeController incomingHeaderController) {
+            @IncomingHeader NodeController incomingHeaderController,
+            @Main DelayableExecutor executor) {
         mHeadsUpManager = headsUpManager;
         mHeadsUpViewBinder = headsUpViewBinder;
         mNotificationInterruptStateProvider = notificationInterruptStateProvider;
         mRemoteInputManager = remoteInputManager;
         mIncomingHeaderController = incomingHeaderController;
+        mExecutor = executor;
     }
 
     @Override
@@ -178,16 +181,26 @@
         public boolean shouldExtendLifetime(@NonNull NotificationEntry entry, int reason) {
             boolean isShowingHun = isCurrentlyShowingHun(entry);
             if (isShowingHun) {
-                mNotifExtendingLifetime = entry;
+                if (isSticky(entry)) {
+                    long removeAfterMillis = mHeadsUpManager.getEarliestRemovalTime(entry.getKey());
+                    if (removeAfterMillis <= 0) return false;
+                    mExecutor.executeDelayed(() -> {
+                        // make sure that the entry was not updated
+                        long removeAfterMillis2 =
+                                mHeadsUpManager.getEarliestRemovalTime(entry.getKey());
+                        if (mNotifsExtendingLifetime.contains(entry) && removeAfterMillis2 <= 0) {
+                            mHeadsUpManager.removeNotification(entry.getKey(), true);
+                        }
+                    }, removeAfterMillis);
+                }
+                mNotifsExtendingLifetime.add(entry);
             }
             return isShowingHun;
         }
 
         @Override
         public void cancelLifetimeExtension(@NonNull NotificationEntry entry) {
-            if (Objects.equals(mNotifExtendingLifetime, entry)) {
-                mNotifExtendingLifetime = null;
-            }
+            mNotifsExtendingLifetime.remove(entry);
         }
     };
 
@@ -220,27 +233,24 @@
             new OnHeadsUpChangedListener() {
         @Override
         public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {
-            NotificationEntry newHUN = mHeadsUpManager.getTopEntry();
-            if (!Objects.equals(mCurrentHun, newHUN)) {
-                mCurrentHun = newHUN;
-                endNotifLifetimeExtension();
-            }
             if (!isHeadsUp) {
                 mHeadsUpViewBinder.unbindHeadsUpView(entry);
+                endNotifLifetimeExtensionIfExtended(entry);
             }
         }
     };
 
-    private boolean isCurrentlyShowingHun(ListEntry entry) {
-        return mCurrentHun == entry.getRepresentativeEntry();
+    private boolean isSticky(NotificationEntry entry) {
+        return mHeadsUpManager.isSticky(entry.getKey());
     }
 
-    private void endNotifLifetimeExtension() {
-        if (mNotifExtendingLifetime != null) {
-            mEndLifetimeExtension.onEndLifetimeExtension(
-                    mLifetimeExtender,
-                    mNotifExtendingLifetime);
-            mNotifExtendingLifetime = null;
+    private boolean isCurrentlyShowingHun(ListEntry entry) {
+        return mHeadsUpManager.isAlerting(entry.getKey());
+    }
+
+    private void endNotifLifetimeExtensionIfExtended(NotificationEntry entry) {
+        if (mNotifsExtendingLifetime.remove(entry)) {
+            mEndLifetimeExtension.onEndLifetimeExtension(mLifetimeExtender, entry);
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
index fe1cd7b..33005b3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
@@ -90,6 +90,7 @@
         readShowSilentNotificationSetting();
 
         setupInvalidateNotifListCallbacks();
+        // Filter at the "finalize" stage so that views remain bound by PreparationCoordinator
         pipeline.addFinalizeFilter(mNotifFilter);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinator.java
index 8769969..ecee006 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinator.java
@@ -49,6 +49,6 @@
 
     @Override
     public void attach(NotifPipeline pipeline) {
-        pipeline.addFinalizeFilter(mMediaFilter);
+        pipeline.addPreGroupFilter(mMediaFilter);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/CommonNotifCollection.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/CommonNotifCollection.java
index 471c357..beaa1ba 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/CommonNotifCollection.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/CommonNotifCollection.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.notification.collection.notifcollection;
 
+import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -37,7 +38,7 @@
      * Registers a listener to be informed when notifications are created, added, updated, removed,
      * or deleted.
      */
-    void addCollectionListener(NotifCollectionListener listener);
+    void addCollectionListener(@NonNull NotifCollectionListener listener);
 
     /**
      * Returns the list of all known notifications, i.e. the notifications that are currently posted
@@ -46,11 +47,11 @@
      *
      * The returned collection is read-only, unsorted, unfiltered, and ungrouped.
      */
-    Collection<NotificationEntry> getAllNotifs();
+    @NonNull Collection<NotificationEntry> getAllNotifs();
 
     /**
      * Returns the notification entry for the given notification key;
      * the returned entry (if present) may be in any state.
      */
-    @Nullable NotificationEntry getEntry(String key);
+    @Nullable NotificationEntry getEntry(@NonNull String key);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/BypassHeadsUpNotifier.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/BypassHeadsUpNotifier.kt
index b2e15f4..b61a540 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/BypassHeadsUpNotifier.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/BypassHeadsUpNotifier.kt
@@ -77,11 +77,11 @@
 
     override fun onPrimaryMetadataOrStateChanged(metadata: MediaMetadata?, state: Int) {
         val previous = currentMediaEntry
-        var newEntry = commonNotifCollection.getEntry(mediaManager.mediaNotificationKey)
-        if (!NotificationMediaManager.isPlayingState(state)) {
-            newEntry = null
-        }
-        currentMediaEntry = newEntry
+        val mediaNotificationKey = mediaManager.mediaNotificationKey
+        currentMediaEntry =
+            if (mediaNotificationKey != null && NotificationMediaManager.isPlayingState(state))
+                commonNotifCollection.getEntry(mediaNotificationKey)
+            else null
         updateAutoHeadsUp(previous)
         updateAutoHeadsUp(currentMediaEntry)
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
index 4b3d6f7..6218c77 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
@@ -23,8 +23,10 @@
 import android.graphics.Rect;
 import android.util.AttributeSet;
 import android.util.IndentingPrintWriter;
+import android.util.Log;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.ViewParent;
 import android.widget.FrameLayout;
 
 import androidx.annotation.Nullable;
@@ -517,6 +519,76 @@
         return mChangingPosition;
     }
 
+    /**
+     * Called when removing a view from its transient container, such as at the end of an animation.
+     * Generally, when operating on ExpandableView instances, this should be used rather than
+     * {@link ExpandableView#removeTransientView(View)} to ensure that the
+     * {@link #getTransientContainer() transient container} is correctly reset.
+     */
+    public void removeFromTransientContainer() {
+        final ViewGroup transientContainer = getTransientContainer();
+        if (transientContainer == null) {
+            return;
+        }
+        final ViewParent parent = getParent();
+        if (parent != transientContainer) {
+            Log.w(TAG, "Expandable view " + this
+                    + " has transient container " + transientContainer
+                    + " but different parent " + parent);
+            setTransientContainer(null);
+            return;
+        }
+        transientContainer.removeTransientView(this);
+        setTransientContainer(null);
+    }
+
+    /**
+     * Called before adding this view to a group, which would always throw an exception if this view
+     * has a different parent, so clean up the transient container and throw an exception if the
+     * parent isn't a transient container.  Provide as much detail as possible in the crash.
+     */
+    public void removeFromTransientContainerForAdditionTo(ViewGroup newParent) {
+        final ViewParent parent = getParent();
+        final ViewGroup transientContainer = getTransientContainer();
+        if (parent == null) {
+            // If this view has no parent, the add will succeed, so just make sure the tracked
+            // transient container is in sync with the lack of a parent.
+            if (transientContainer != null) {
+                Log.w(TAG, "Expandable view " + this
+                        + " has transient container " + transientContainer
+                        + " but no parent");
+                setTransientContainer(null);
+            }
+            return;
+        }
+        if (transientContainer == null) {
+            throw new IllegalStateException(
+                    "Can't add view " + this + " to container " + newParent + "; current parent "
+                            + parent + " is not a transient container");
+        }
+        if (transientContainer != parent) {
+            String transientContainerOutOfSyncError = "Expandable view " + this
+                    + " has transient container " + transientContainer
+                    + " but different parent " + parent;
+            if (parent != newParent) {
+                // Crash with details before addView() crashes without any; the view is being added
+                // to a different parent, and the transient container isn't the parent, so we can't
+                // even (safely) clean that up.
+                throw new IllegalStateException(transientContainerOutOfSyncError);
+            } else {
+                Log.w(TAG, transientContainerOutOfSyncError);
+                setTransientContainer(null);
+                return;
+            }
+        }
+        if (parent != newParent) {
+            Log.w(TAG, "Moving view " + this + " from transient container "
+                    + transientContainer + " to parent " + newParent);
+        }
+        transientContainer.removeTransientView(this);
+        setTransientContainer(null);
+    }
+
     public void setTransientContainer(ViewGroup transientContainer) {
         mTransientContainer = transientContainer;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
index 3a37fb4..9d599cb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
@@ -41,11 +41,8 @@
 import android.widget.FrameLayout.LayoutParams;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.animation.Interpolators;
-import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.flags.Flags;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
 import com.android.systemui.statusbar.AlphaOptimizedImageView;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -304,12 +301,9 @@
         } else {
             mMenuContainer = new FrameLayout(mContext);
         }
-        // The setting can win (which is needed for tests) but if not set, then use the flag
         final int showDismissSetting =  Settings.Global.getInt(mContext.getContentResolver(),
-                Settings.Global.SHOW_NEW_NOTIF_DISMISS, -1);
-        final boolean newFlowHideShelf = showDismissSetting == -1
-                ? Dependency.get(FeatureFlags.class).isEnabled(Flags.NOTIFICATION_UPDATES)
-                : showDismissSetting == 1;
+                Settings.Global.SHOW_NEW_NOTIF_DISMISS, /* default = */ 1);
+        final boolean newFlowHideShelf = showDismissSetting == 1;
         if (newFlowHideShelf) {
             return;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
index 046a133..a3fe47c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
@@ -44,6 +44,7 @@
 import com.android.systemui.statusbar.notification.NotificationUtils;
 import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.systemui.statusbar.notification.row.ExpandableView;
 import com.android.systemui.statusbar.notification.row.HybridGroupManager;
 import com.android.systemui.statusbar.notification.row.HybridNotificationView;
 import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
@@ -272,6 +273,7 @@
      * @param childIndex the index to add it at, if -1 it will be added at the end
      */
     public void addNotification(ExpandableNotificationRow row, int childIndex) {
+        ensureRemovedFromTransientContainer(row);
         int newIndex = childIndex < 0 ? mAttachedChildren.size() : childIndex;
         mAttachedChildren.add(newIndex, row);
         addView(row);
@@ -291,6 +293,16 @@
         }
     }
 
+    private void ensureRemovedFromTransientContainer(View v) {
+        if (v.getParent() != null && v instanceof ExpandableView) {
+            // If the child is animating away, it will still have a parent, so detach it first
+            // TODO: We should really cancel the active animations here. This will
+            //  happen automatically when the view's intro animation starts, but
+            //  it's a fragile link.
+            ((ExpandableView) v).removeFromTransientContainerForAdditionTo(this);
+        }
+    }
+
     public void removeNotification(ExpandableNotificationRow row) {
         int childIndex = mAttachedChildren.indexOf(row);
         mAttachedChildren.remove(row);
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 1cb5e62..464fd06 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
@@ -21,8 +21,6 @@
 
 import com.android.systemui.R;
 import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.flags.Flags;
 import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.ExpandableView;
@@ -41,7 +39,6 @@
     private final ExpandableView[] mLastInSectionViews;
     private final ExpandableView[] mTmpFirstInSectionViews;
     private final ExpandableView[] mTmpLastInSectionViews;
-    private final FeatureFlags mFeatureFlags;
     private boolean mExpanded;
     private HashSet<ExpandableView> mAnimatedChildren;
     private Runnable mRoundingChangedCallback;
@@ -56,9 +53,7 @@
 
     @Inject
     NotificationRoundnessManager(
-            NotificationSectionsFeatureManager sectionsFeatureManager,
-            FeatureFlags featureFlags) {
-        mFeatureFlags = featureFlags;
+            NotificationSectionsFeatureManager sectionsFeatureManager) {
         int numberOfSections = sectionsFeatureManager.getNumberOfBuckets();
         mFirstInSectionViews = new ExpandableView[numberOfSections];
         mLastInSectionViews = new ExpandableView[numberOfSections];
@@ -125,9 +120,6 @@
             ExpandableView viewBefore,
             ExpandableView viewSwiped,
             ExpandableView viewAfter) {
-        if (!mFeatureFlags.isEnabled(Flags.NOTIFICATION_UPDATES)) {
-            return;
-        }
         final boolean animate = true;
 
         ExpandableView oldViewBefore = mViewBeforeSwipedView;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
index 88198f3..1d90780 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
@@ -215,8 +215,7 @@
                             // TODO: We should really cancel the active animations here. This will
                             //  happen automatically when the view's intro animation starts, but
                             //  it's a fragile link.
-                            header.transientContainer?.removeTransientView(header)
-                            header.transientContainer = null
+                            header.removeFromTransientContainer()
                             parent.addView(header, target)
                         } else {
                             parent.changeViewPosition(header, target)
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 79b05c9..943f05f 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
@@ -43,7 +43,6 @@
 import android.graphics.PointF;
 import android.graphics.Rect;
 import android.os.Bundle;
-import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.util.AttributeSet;
@@ -80,6 +79,8 @@
 import com.android.systemui.ExpandHelper;
 import com.android.systemui.R;
 import com.android.systemui.animation.Interpolators;
+import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
 import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.EmptyShadeView;
@@ -132,14 +133,6 @@
     public static final float BACKGROUND_ALPHA_DIMMED = 0.7f;
     private static final String TAG = "StackScroller";
 
-    // Usage:
-    // adb shell setprop persist.debug.nssl true && adb reboot
-    private static final boolean DEBUG = SystemProperties.getBoolean("persist.debug.nssl",
-            false /* default */);
-    // TODO(b/187291379) disable again before release
-    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;
@@ -192,7 +185,12 @@
     private float mInitialTouchX;
     private float mInitialTouchY;
 
+    private final boolean mDebugLines;
     private Paint mDebugPaint;
+    /** Used to track the Y positions that were already used to draw debug text labels. */
+    private Set<Integer> mDebugTextUsedYPositions;
+    private final boolean mDebugRemoveAnimation;
+
     private int mContentHeight;
     private int mIntrinsicContentHeight;
     private int mCollapsedSize;
@@ -569,6 +567,9 @@
     public NotificationStackScrollLayout(Context context, AttributeSet attrs) {
         super(context, attrs, 0, 0);
         Resources res = getResources();
+        FeatureFlags featureFlags = Dependency.get(FeatureFlags.class);
+        mDebugLines = featureFlags.isEnabled(Flags.NSSL_DEBUG_LINES);
+        mDebugRemoveAnimation = featureFlags.isEnabled(Flags.NSSL_DEBUG_REMOVE_ANIMATION);
         mSectionsManager = Dependency.get(NotificationSectionsManager.class);
         mScreenOffAnimationController =
                 Dependency.get(ScreenOffAnimationController.class);
@@ -591,10 +592,10 @@
                 res.getBoolean(R.bool.config_drawNotificationBackground);
         setOutlineProvider(mOutlineProvider);
 
-        boolean willDraw = mShouldDrawNotificationBackground || DEBUG;
+        boolean willDraw = mShouldDrawNotificationBackground || mDebugLines;
         setWillNotDraw(!willDraw);
         mBackgroundPaint.setAntiAlias(true);
-        if (DEBUG) {
+        if (mDebugLines) {
             mDebugPaint = new Paint();
             mDebugPaint.setColor(0xffff0000);
             mDebugPaint.setStrokeWidth(2);
@@ -729,18 +730,17 @@
             drawHeadsUpBackground(canvas);
         }
 
-        if (DEBUG) {
+        if (mDebugLines) {
             onDrawDebug(canvas);
         }
     }
 
-    /** Used to track the Y positions that were already used to draw debug text labels. */
-    private static final Set<Integer> DEBUG_TEXT_USED_Y_POSITIONS =
-            DEBUG ? new HashSet<>() : Collections.emptySet();
-
     private void onDrawDebug(Canvas canvas) {
-        DEBUG_TEXT_USED_Y_POSITIONS.clear();
-
+        if (mDebugTextUsedYPositions == null) {
+            mDebugTextUsedYPositions = new HashSet<>();
+        } else {
+            mDebugTextUsedYPositions.clear();
+        }
         int y = mTopPadding;
         drawDebugInfo(canvas, y, Color.RED, /* label= */ "mTopPadding");
 
@@ -776,10 +776,10 @@
 
     private int computeDebugYTextPosition(int lineY) {
         int textY = lineY;
-        while (DEBUG_TEXT_USED_Y_POSITIONS.contains(textY)) {
+        while (mDebugTextUsedYPositions.contains(textY)) {
             textY = (int) (textY + mDebugPaint.getTextSize());
         }
-        DEBUG_TEXT_USED_Y_POSITIONS.add(textY);
+        mDebugTextUsedYPositions.add(textY);
         return textY;
     }
 
@@ -2702,14 +2702,14 @@
     @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
     boolean generateRemoveAnimation(ExpandableView child) {
         String key = "";
-        if (DEBUG_REMOVE_ANIMATION) {
+        if (mDebugRemoveAnimation) {
             if (child instanceof ExpandableNotificationRow) {
                 key = ((ExpandableNotificationRow) child).getEntry().getKey();
             }
             Log.d(TAG, "generateRemoveAnimation " + key);
         }
         if (removeRemovedChildFromHeadsUpChangeAnimations(child)) {
-            if (DEBUG_REMOVE_ANIMATION) {
+            if (mDebugRemoveAnimation) {
                 Log.d(TAG, "removedBecauseOfHeadsUp " + key);
             }
             mAddedHeadsUpChildren.remove(child);
@@ -2720,7 +2720,7 @@
             mClearTransientViewsWhenFinished.add(child);
             return true;
         }
-        if (DEBUG_REMOVE_ANIMATION) {
+        if (mDebugRemoveAnimation) {
             Log.d(TAG, "generateRemove " + key
                     + "\nmIsExpanded " + mIsExpanded
                     + "\nmAnimationsEnabled " + mAnimationsEnabled
@@ -2728,7 +2728,7 @@
         }
         if (mIsExpanded && mAnimationsEnabled && !isChildInInvisibleGroup(child)) {
             if (!mChildrenToAddAnimated.contains(child)) {
-                if (DEBUG_REMOVE_ANIMATION) {
+                if (mDebugRemoveAnimation) {
                     Log.d(TAG, "needsAnimation = true " + key);
                 }
                 // Generate Animations
@@ -3213,10 +3213,7 @@
                     // Clean up any potential transient views if the child has already been swiped
                     // out, as we won't be animating it further (due to its height already being
                     // clipped to 0.
-                    ViewGroup transientContainer = child.getTransientContainer();
-                    if (transientContainer != null) {
-                        transientContainer.removeTransientView(child);
-                    }
+                    child.removeFromTransientContainer();
                 }
             }
             int animationType = childWasSwipedOut
@@ -3227,7 +3224,7 @@
                     ignoreChildren);
             mAnimationEvents.add(event);
             mSwipedOutViews.remove(child);
-            if (DEBUG_REMOVE_ANIMATION) {
+            if (mDebugRemoveAnimation) {
                 String key = "";
                 if (child instanceof ExpandableNotificationRow) {
                     key = ((ExpandableNotificationRow) child).getEntry().getKey();
@@ -3933,7 +3930,11 @@
     @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
     private void clearTemporaryViewsInGroup(ViewGroup viewGroup) {
         while (viewGroup != null && viewGroup.getTransientViewCount() != 0) {
-            viewGroup.removeTransientView(viewGroup.getTransientView(0));
+            final View transientView = viewGroup.getTransientView(0);
+            viewGroup.removeTransientView(transientView);
+            if (transientView instanceof ExpandableView) {
+                ((ExpandableView) transientView).setTransientContainer(null);
+            }
         }
     }
 
@@ -4102,7 +4103,7 @@
     @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
     private void clearTransient() {
         for (ExpandableView view : mClearTransientViewsWhenFinished) {
-            StackStateAnimator.removeTransientView(view);
+            view.removeFromTransientContainer();
         }
         mClearTransientViewsWhenFinished.clear();
     }
@@ -4655,18 +4656,12 @@
     }
 
     private void ensureRemovedFromTransientContainer(View v) {
-        if (v.getParent() == this && v instanceof ExpandableView) {
-            ExpandableView expandableView = (ExpandableView) v;
-            ViewGroup transientContainer = expandableView.getTransientContainer();
-            // If the child is animating away, it will still have a parent, so
-            // detach it first
+        if (v.getParent() != null && v instanceof ExpandableView) {
+            // If the child is animating away, it will still have a parent, so detach it first
             // TODO: We should really cancel the active animations here. This will
             //  happen automatically when the view's intro animation starts, but
             //  it's a fragile link.
-            if (transientContainer != null) {
-                transientContainer.removeTransientView(v);
-                expandableView.setTransientContainer(null);
-            }
+            ((ExpandableView) v).removeFromTransientContainerForAdditionTo(this);
         }
     }
 
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 41a80c7..fc612a9 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,7 @@
     private final NotificationGroupManagerLegacy mLegacyGroupManager;
     private final SectionHeaderController mSilentHeaderController;
     private final LockscreenShadeTransitionController mLockscreenShadeTransitionController;
+    private final InteractionJankMonitor mJankMonitor;
 
     private NotificationStackScrollLayout mView;
     private boolean mFadeNotificationsOnDismiss;
@@ -454,10 +455,7 @@
                     if (!row.isDismissed()) {
                         handleChildViewDismissed(view);
                     }
-                    ViewGroup transientContainer = row.getTransientContainer();
-                    if (transientContainer != null) {
-                        transientContainer.removeTransientView(view);
-                    }
+                    row.removeFromTransientContainer();
                 }
 
                 /**
@@ -661,7 +659,8 @@
             LayoutInflater layoutInflater,
             NotificationRemoteInputManager remoteInputManager,
             VisualStabilityManager visualStabilityManager,
-            ShadeController shadeController) {
+            ShadeController shadeController,
+            InteractionJankMonitor jankMonitor) {
         mAllowLongPress = allowLongPress;
         mNotificationGutsManager = notificationGutsManager;
         mVisibilityProvider = visibilityProvider;
@@ -684,6 +683,7 @@
         mNotificationSwipeHelperBuilder = notificationSwipeHelperBuilder;
         mStatusBar = statusBar;
         mScrimController = scrimController;
+        mJankMonitor = jankMonitor;
         groupManager.registerGroupExpansionChangeListener(
                 (changedRow, expanded) -> mView.onGroupExpandChanged(changedRow, expanded));
         legacyGroupManager.registerGroupChangeListener(new OnGroupChangeListener() {
@@ -1784,9 +1784,9 @@
             // We log any touches other than down, which will be captured by onTouchEvent.
             // In the intercept we only start tracing when it's not a down (otherwise that down
             // would be duplicated when intercepted).
-            if (scrollWantsIt && ev.getActionMasked() != MotionEvent.ACTION_DOWN) {
-                InteractionJankMonitor.getInstance().begin(mView,
-                        CUJ_NOTIFICATION_SHADE_SCROLL_FLING);
+            if (mJankMonitor != null && scrollWantsIt
+                    && ev.getActionMasked() != MotionEvent.ACTION_DOWN) {
+                mJankMonitor.begin(mView, CUJ_NOTIFICATION_SHADE_SCROLL_FLING);
             }
             return swipeWantsIt || scrollWantsIt || expandWantsIt || longPressWantsIt;
         }
@@ -1854,24 +1854,25 @@
         }
 
         private void traceJankOnTouchEvent(int action, boolean scrollerWantsIt) {
+            if (mJankMonitor == null) {
+                Log.w(TAG, "traceJankOnTouchEvent, mJankMonitor is null");
+                return;
+            }
             // Handle interaction jank monitor cases.
             switch (action) {
                 case MotionEvent.ACTION_DOWN:
                     if (scrollerWantsIt) {
-                        InteractionJankMonitor.getInstance()
-                                .begin(mView, CUJ_NOTIFICATION_SHADE_SCROLL_FLING);
+                        mJankMonitor.begin(mView, CUJ_NOTIFICATION_SHADE_SCROLL_FLING);
                     }
                     break;
                 case MotionEvent.ACTION_UP:
                     if (scrollerWantsIt && !mView.isFlingAfterUpEvent()) {
-                        InteractionJankMonitor.getInstance()
-                                .end(CUJ_NOTIFICATION_SHADE_SCROLL_FLING);
+                        mJankMonitor.end(CUJ_NOTIFICATION_SHADE_SCROLL_FLING);
                     }
                     break;
                 case MotionEvent.ACTION_CANCEL:
                     if (scrollerWantsIt) {
-                        InteractionJankMonitor.getInstance()
-                                .cancel(CUJ_NOTIFICATION_SHADE_SCROLL_FLING);
+                        mJankMonitor.cancel(CUJ_NOTIFICATION_SHADE_SCROLL_FLING);
                     }
                     break;
             }
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 2dc9276..1d0d374 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
@@ -322,9 +322,8 @@
     private void onAnimationFinished() {
         mHostLayout.onChildAnimationFinished();
 
-        for (ExpandableView transientViewsToRemove : mTransientViewsToRemove) {
-            transientViewsToRemove.getTransientContainer()
-                    .removeTransientView(transientViewsToRemove);
+        for (ExpandableView transientViewToRemove : mTransientViewsToRemove) {
+            transientViewToRemove.removeFromTransientContainer();
         }
         mTransientViewsToRemove.clear();
     }
@@ -353,7 +352,7 @@
             } else if (event.animationType ==
                     NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_REMOVE) {
                 if (changingView.getVisibility() != View.VISIBLE) {
-                    removeTransientView(changingView);
+                    changingView.removeFromTransientContainer();
                     continue;
                 }
 
@@ -390,12 +389,11 @@
                 }
                 changingView.performRemoveAnimation(ANIMATION_DURATION_APPEAR_DISAPPEAR,
                         0 /* delay */, translationDirection, false /* isHeadsUpAppear */,
-                        0, () -> removeTransientView(changingView), null);
+                        0, changingView::removeFromTransientContainer, null);
             } else if (event.animationType ==
                 NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_REMOVE_SWIPED_OUT) {
-                if (mHostLayout.isFullySwipedOut(changingView)
-                        && changingView.getTransientContainer() != null) {
-                    changingView.getTransientContainer().removeTransientView(changingView);
+                if (mHostLayout.isFullySwipedOut(changingView)) {
+                    changingView.removeFromTransientContainer();
                 }
             } else if (event.animationType == NotificationStackScrollLayout
                     .AnimationEvent.ANIMATION_TYPE_GROUP_EXPANSION_CHANGED) {
@@ -425,7 +423,7 @@
                     mHostLayout.addTransientView(changingView, 0);
                     changingView.setTransientContainer(mHostLayout);
                     mTmpState.initFrom(changingView);
-                    endRunnable = () -> removeTransientView(changingView);
+                    endRunnable = changingView::removeFromTransientContainer;
                 }
                 float targetLocation = 0;
                 boolean needsAnimation = true;
@@ -468,12 +466,6 @@
         }
     }
 
-    public static void removeTransientView(ExpandableView viewToRemove) {
-        if (viewToRemove.getTransientContainer() != null) {
-            viewToRemove.getTransientContainer().removeTransientView(viewToRemove);
-        }
-    }
-
     public void animateOverScrollToAmount(float targetAmount, final boolean onTop,
             final boolean isRubberbanded) {
         final float startOverScrollAmount = mHostLayout.getCurrentOverScrollAmount(onTop);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
index ad1c232..bfa4a24 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -634,20 +634,22 @@
         Optional.ofNullable(BiometricUiEvent.FAILURE_EVENT_BY_SOURCE_TYPE.get(biometricSourceType))
                 .ifPresent(UI_EVENT_LOGGER::log);
 
-        long currUptimeMillis = SystemClock.uptimeMillis();
-        if (currUptimeMillis - mLastFpFailureUptimeMillis < 2000) { // attempt within 2 seconds
-            mNumConsecutiveFpFailures += 1;
-        } else {
-            mNumConsecutiveFpFailures = 1;
-        }
-        mLastFpFailureUptimeMillis = currUptimeMillis;
+        if (biometricSourceType == BiometricSourceType.FINGERPRINT
+                && mUpdateMonitor.isUdfpsSupported()) {
+            long currUptimeMillis = SystemClock.uptimeMillis();
+            if (currUptimeMillis - mLastFpFailureUptimeMillis
+                    < (mStatusBarStateController.isDozing() ? 3500 : 2000)) {
+                mNumConsecutiveFpFailures += 1;
+            } else {
+                mNumConsecutiveFpFailures = 1;
+            }
+            mLastFpFailureUptimeMillis = currUptimeMillis;
 
-        if (biometricSourceType.equals(BiometricSourceType.FINGERPRINT)
-                && mUpdateMonitor.isUdfpsSupported()
-                && mNumConsecutiveFpFailures >= FP_ATTEMPTS_BEFORE_SHOW_BOUNCER) {
-            mKeyguardViewController.showBouncer(true);
-            UI_EVENT_LOGGER.log(BiometricUiEvent.BIOMETRIC_BOUNCER_SHOWN);
-            mNumConsecutiveFpFailures = 0;
+            if (mNumConsecutiveFpFailures >= FP_ATTEMPTS_BEFORE_SHOW_BOUNCER) {
+                startWakeAndUnlock(MODE_SHOW_BOUNCER);
+                UI_EVENT_LOGGER.log(BiometricUiEvent.BIOMETRIC_BOUNCER_SHOWN);
+                mNumConsecutiveFpFailures = 0;
+            }
         }
         cleanup();
     }
@@ -668,7 +670,8 @@
                 && mUpdateMonitor.isUdfpsSupported()
                 && (mStatusBarStateController.getState() == StatusBarState.SHADE
                     || mStatusBarStateController.getState() == StatusBarState.SHADE_LOCKED)) {
-            mKeyguardViewController.showBouncer(true);
+            startWakeAndUnlock(MODE_SHOW_BOUNCER);
+            UI_EVENT_LOGGER.log(BiometricUiEvent.BIOMETRIC_BOUNCER_SHOWN);
         }
         cleanup();
     }
@@ -735,6 +738,11 @@
         pw.println(" BiometricUnlockController:");
         pw.print("   mMode="); pw.println(mMode);
         pw.print("   mWakeLock="); pw.println(mWakeLock);
+        if (mUpdateMonitor.isUdfpsSupported()) {
+            pw.print("   mNumConsecutiveFpFailures="); pw.println(mNumConsecutiveFpFailures);
+            pw.print("   time since last failure=");
+            pw.println(SystemClock.uptimeMillis() - mLastFpFailureUptimeMillis);
+        }
     }
 
     /**
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 d87a024..1b42b58 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.phone;
 
+import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.hardware.display.AmbientDisplayConfiguration;
 import android.os.PowerManager;
@@ -26,7 +27,10 @@
 import android.util.MathUtils;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.VisibleForTesting;
 
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.systemui.Dumpable;
 import com.android.systemui.R;
 import com.android.systemui.dagger.SysUISingleton;
@@ -36,13 +40,18 @@
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.flags.Flags;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.DevicePostureController;
 import com.android.systemui.tuner.TunerService;
+import com.android.systemui.unfold.FoldAodAnimationController;
+import com.android.systemui.unfold.SysUIUnfoldComponent;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.HashSet;
+import java.util.Optional;
 import java.util.Set;
 
 import javax.inject.Inject;
@@ -54,7 +63,8 @@
 public class DozeParameters implements
         TunerService.Tunable,
         com.android.systemui.plugins.statusbar.DozeParameters,
-        Dumpable {
+        Dumpable, ConfigurationController.ConfigurationListener,
+        StatusBarStateController.StateListener, FoldAodAnimationController.FoldAodAnimationStatus {
     private static final int MAX_DURATION = 60 * 1000;
     public static final boolean FORCE_NO_BLANKING =
             SystemProperties.getBoolean("debug.force_no_blanking", false);
@@ -69,12 +79,30 @@
     private final BatteryController mBatteryController;
     private final FeatureFlags mFeatureFlags;
     private final ScreenOffAnimationController mScreenOffAnimationController;
+    private final FoldAodAnimationController mFoldAodAnimationController;
+    private final UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
 
     private final Set<Callback> mCallbacks = new HashSet<>();
 
     private boolean mDozeAlwaysOn;
     private boolean mControlScreenOffAnimation;
 
+    private boolean mKeyguardShowing;
+    @VisibleForTesting
+    final KeyguardUpdateMonitorCallback mKeyguardVisibilityCallback =
+            new KeyguardUpdateMonitorCallback() {
+                @Override
+                public void onKeyguardVisibilityChanged(boolean showing) {
+                    mKeyguardShowing = showing;
+                    updateControlScreenOff();
+                }
+
+                @Override
+                public void onShadeExpandedChanged(boolean expanded) {
+                    updateControlScreenOff();
+                }
+            };
+
     @Inject
     protected DozeParameters(
             @Main Resources resources,
@@ -85,7 +113,12 @@
             TunerService tunerService,
             DumpManager dumpManager,
             FeatureFlags featureFlags,
-            ScreenOffAnimationController screenOffAnimationController) {
+            ScreenOffAnimationController screenOffAnimationController,
+            Optional<SysUIUnfoldComponent> sysUiUnfoldComponent,
+            UnlockedScreenOffAnimationController unlockedScreenOffAnimationController,
+            KeyguardUpdateMonitor keyguardUpdateMonitor,
+            ConfigurationController configurationController,
+            StatusBarStateController statusBarStateController) {
         mResources = resources;
         mAmbientDisplayConfiguration = ambientDisplayConfiguration;
         mAlwaysOnPolicy = alwaysOnDisplayPolicy;
@@ -97,11 +130,22 @@
         mPowerManager.setDozeAfterScreenOff(!mControlScreenOffAnimation);
         mFeatureFlags = featureFlags;
         mScreenOffAnimationController = screenOffAnimationController;
+        mUnlockedScreenOffAnimationController = unlockedScreenOffAnimationController;
 
+        keyguardUpdateMonitor.registerCallback(mKeyguardVisibilityCallback);
         tunerService.addTunable(
                 this,
                 Settings.Secure.DOZE_ALWAYS_ON,
                 Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED);
+        configurationController.addCallback(this);
+        statusBarStateController.addCallback(this);
+
+        mFoldAodAnimationController = sysUiUnfoldComponent
+                .map(SysUIUnfoldComponent::getFoldAodAnimationController).orElse(null);
+
+        if (mFoldAodAnimationController != null) {
+            mFoldAodAnimationController.addCallback(this);
+        }
     }
 
     public boolean getDisplayStateSupported() {
@@ -222,13 +266,26 @@
         mPowerManager.setDozeAfterScreenOff(!controlScreenOffAnimation);
     }
 
+    public void updateControlScreenOff() {
+        if (!getDisplayNeedsBlanking()) {
+            final boolean controlScreenOff =
+                    getAlwaysOn() && (mKeyguardShowing || shouldControlUnlockedScreenOff());
+            setControlScreenOffAnimation(controlScreenOff);
+        }
+    }
+
     /**
      * Whether we want to control the screen off animation when the device is unlocked. If we do,
      * we'll animate in AOD before turning off the screen, rather than simply fading to black and
      * then abruptly showing AOD.
+     *
+     * There are currently several reasons we might not want to control the screen off even if we
+     * are able to, such as the shade being expanded, being in landscape, or having animations
+     * disabled for a11y.
      */
     public boolean shouldControlUnlockedScreenOff() {
-        return mScreenOffAnimationController.shouldControlUnlockedScreenOff();
+        return canControlUnlockedScreenOff()
+                && mUnlockedScreenOffAnimationController.shouldPlayUnlockedScreenOffAnimation();
     }
 
     public boolean shouldDelayKeyguardShow() {
@@ -325,6 +382,11 @@
     @Override
     public void onTuningChanged(String key, String newValue) {
         mDozeAlwaysOn = mAmbientDisplayConfiguration.alwaysOnEnabled(UserHandle.USER_CURRENT);
+
+        if (key.equals(Settings.Secure.DOZE_ALWAYS_ON)) {
+            updateControlScreenOff();
+        }
+
         for (Callback callback : mCallbacks) {
             callback.onAlwaysOnChange();
         }
@@ -332,6 +394,21 @@
     }
 
     @Override
+    public void onConfigChanged(Configuration newConfig) {
+        updateControlScreenOff();
+    }
+
+    @Override
+    public void onStatePostChange() {
+        updateControlScreenOff();
+    }
+
+    @Override
+    public void onFoldToAodAnimationChanged() {
+        updateControlScreenOff();
+    }
+
+    @Override
     public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
         pw.print("getAlwaysOn(): "); pw.println(getAlwaysOn());
         pw.print("getDisplayStateSupported(): "); pw.println(getDisplayStateSupported());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
index 57b9c03..b35e684 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
@@ -63,7 +63,6 @@
     private final DozeLog mDozeLog;
     private final PowerManager mPowerManager;
     private boolean mAnimateWakeup;
-    private boolean mAnimateScreenOff;
     private boolean mIgnoreTouchWhilePulsing;
     private Runnable mPendingScreenOffCallback;
     @VisibleForTesting
@@ -255,7 +254,6 @@
 
             private void setPulsing(boolean pulsing) {
                 mStatusBarKeyguardViewManager.setPulsing(pulsing);
-                mKeyguardViewMediator.setPulsing(pulsing);
                 mNotificationPanel.setPulsing(pulsing);
                 mStatusBarStateController.setPulsing(pulsing);
                 mIgnoreTouchWhilePulsing = false;
@@ -357,11 +355,6 @@
     }
 
     @Override
-    public void setAnimateScreenOff(boolean animateScreenOff) {
-        mAnimateScreenOff = animateScreenOff;
-    }
-
-    @Override
     public void onSlpiTap(float screenX, float screenY) {
         if (screenX > 0 && screenY > 0 && mAmbientIndicationContainer != null
                 && mAmbientIndicationContainer.getVisibility() == View.VISIBLE) {
@@ -440,10 +433,6 @@
         return mAnimateWakeup;
     }
 
-    boolean shouldAnimateScreenOff() {
-        return mAnimateScreenOff;
-    }
-
     boolean getIgnoreTouchWhilePulsing() {
         return mIgnoreTouchWhilePulsing;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FoldStateListener.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FoldStateListener.kt
new file mode 100644
index 0000000..56b0d598
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FoldStateListener.kt
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.statusbar.phone
+
+import android.content.Context
+import android.hardware.devicestate.DeviceStateManager.DeviceStateCallback
+import com.android.internal.R
+
+/**
+ * Listens for fold state changes and reports the new folded state together with other properties
+ * associated with that state.
+ */
+internal class FoldStateListener(
+    context: Context,
+    private val listener: OnFoldStateChangeListener
+) : DeviceStateCallback {
+
+    internal interface OnFoldStateChangeListener {
+        /**
+         * Reports that the device either became folded or unfolded.
+         *
+         * @param folded whether the device is folded.
+         * @param willGoToSleep whether the device will go to sleep and keep the screen off.
+         */
+        fun onFoldStateChanged(folded: Boolean, willGoToSleep: Boolean)
+    }
+
+    private val foldedDeviceStates: IntArray =
+        context.resources.getIntArray(R.array.config_foldedDeviceStates)
+    private val goToSleepDeviceStates: IntArray =
+        context.resources.getIntArray(R.array.config_deviceStatesOnWhichToSleep)
+
+    private var wasFolded: Boolean? = null
+
+    override fun onStateChanged(state: Int) {
+        val isFolded = foldedDeviceStates.contains(state)
+        if (wasFolded == isFolded) {
+            return
+        }
+        wasFolded = isFolded
+        val willGoToSleep = goToSleepDeviceStates.contains(state)
+        listener.onFoldStateChanged(isFolded, willGoToSleep)
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index 9647486..565b2d3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -33,7 +33,6 @@
 
 import com.android.internal.policy.SystemBarUtils;
 import com.android.keyguard.KeyguardHostViewController;
-import com.android.keyguard.KeyguardRootViewController;
 import com.android.keyguard.KeyguardSecurityModel;
 import com.android.keyguard.KeyguardSecurityView;
 import com.android.keyguard.KeyguardUpdateMonitor;
@@ -42,7 +41,6 @@
 import com.android.keyguard.dagger.KeyguardBouncerComponent;
 import com.android.systemui.DejankUtils;
 import com.android.systemui.classifier.FalsingCollector;
-import com.android.systemui.dagger.qualifiers.RootView;
 import com.android.systemui.keyguard.DismissCallbackRegistry;
 import com.android.systemui.shared.system.SysUiStatsLog;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -105,12 +103,11 @@
 
     private int mStatusBarHeight;
     private float mExpansion = EXPANSION_HIDDEN;
-    protected ViewGroup mRoot;
-    private KeyguardRootViewController mRootViewController;
     private boolean mShowingSoon;
     private int mBouncerPromptReason;
     private boolean mIsAnimatingAway;
     private boolean mIsScrimmed;
+    private boolean mInitialized;
 
     private KeyguardBouncer(Context context, ViewMediatorCallback callback,
             ViewGroup container,
@@ -184,7 +181,7 @@
             showPrimarySecurityScreen();
         }
 
-        if (mRoot.getVisibility() == View.VISIBLE || mShowingSoon) {
+        if (mContainer.getVisibility() == View.VISIBLE || mShowingSoon) {
             return;
         }
 
@@ -235,10 +232,8 @@
             Log.wtf(TAG, "onFullyShown when view was null");
         } else {
             mKeyguardViewController.onResume();
-            if (mRoot != null) {
-                mRoot.announceForAccessibility(
-                        mKeyguardViewController.getAccessibilityTitleForCurrentMode());
-            }
+            mContainer.announceForAccessibility(
+                    mKeyguardViewController.getAccessibilityTitleForCurrentMode());
         }
     }
 
@@ -253,10 +248,8 @@
     }
 
     private void setVisibility(@View.Visibility int visibility) {
-        if (mRoot != null) {
-            mRoot.setVisibility(visibility);
-            dispatchVisibilityChanged();
-        }
+        mContainer.setVisibility(visibility);
+        dispatchVisibilityChanged();
     }
 
     private final Runnable mShowRunnable = new Runnable() {
@@ -337,14 +330,12 @@
             mKeyguardViewController.cleanUp();
         }
         mIsAnimatingAway = false;
-        if (mRoot != null) {
-            setVisibility(View.INVISIBLE);
-            if (destroyView) {
+        setVisibility(View.INVISIBLE);
+        if (destroyView) {
 
-                // We have a ViewFlipper that unregisters a broadcast when being detached, which may
-                // be slow because of AM lock contention during unlocking. We can delay it a bit.
-                mHandler.postDelayed(mRemoveViewRunnable, 50);
-            }
+            // We have a ViewFlipper that unregisters a broadcast when being detached, which may
+            // be slow because of AM lock contention during unlocking. We can delay it a bit.
+            mHandler.postDelayed(mRemoveViewRunnable, 50);
         }
     }
 
@@ -370,14 +361,13 @@
     }
 
     public void onScreenTurnedOff() {
-        if (mKeyguardViewController != null
-                && mRoot != null && mRoot.getVisibility() == View.VISIBLE) {
+        if (mKeyguardViewController != null && mContainer.getVisibility() == View.VISIBLE) {
             mKeyguardViewController.onPause();
         }
     }
 
     public boolean isShowing() {
-        return (mShowingSoon || (mRoot != null && mRoot.getVisibility() == View.VISIBLE))
+        return (mShowingSoon || mContainer.getVisibility() == View.VISIBLE)
                 && mExpansion == EXPANSION_VISIBLE && !isAnimatingAway();
     }
 
@@ -401,7 +391,7 @@
     }
 
     public void prepare() {
-        boolean wasInitialized = mRoot != null;
+        boolean wasInitialized = mInitialized;
         ensureView();
         if (wasInitialized) {
             showPrimarySecurityScreen();
@@ -461,7 +451,7 @@
         // in this case we need to force the removal, otherwise we'll
         // end up in an unpredictable state.
         boolean forceRemoval = mHandler.hasCallbacks(mRemoveViewRunnable);
-        if (mRoot == null || forceRemoval) {
+        if (!mInitialized || forceRemoval) {
             inflateView();
         }
     }
@@ -469,28 +459,24 @@
     protected void inflateView() {
         removeView();
         mHandler.removeCallbacks(mRemoveViewRunnable);
-        KeyguardBouncerComponent component = mKeyguardBouncerComponentFactory.create();
-        mRootViewController = component.getKeyguardRootViewController();
-        mRootViewController.init();
-        mRoot = mRootViewController.getView();  // TODO(b/166448040): Don't access root view here.
+
+        KeyguardBouncerComponent component = mKeyguardBouncerComponentFactory.create(mContainer);
         mKeyguardViewController = component.getKeyguardHostViewController();
         mKeyguardViewController.init();
 
-        mContainer.addView(mRoot, mContainer.getChildCount());
         mStatusBarHeight = SystemBarUtils.getStatusBarHeight(mContext);
         setVisibility(View.INVISIBLE);
 
-        final WindowInsets rootInsets = mRoot.getRootWindowInsets();
+        final WindowInsets rootInsets = mContainer.getRootWindowInsets();
         if (rootInsets != null) {
-            mRoot.dispatchApplyWindowInsets(rootInsets);
+            mContainer.dispatchApplyWindowInsets(rootInsets);
         }
+        mInitialized = true;
     }
 
     protected void removeView() {
-        if (mRoot != null && mRoot.getParent() == mContainer) {
-            mContainer.removeView(mRoot);
-            mRoot = null;
-        }
+        mContainer.removeAllViews();
+        mInitialized = false;
     }
 
     /**
@@ -577,7 +563,7 @@
 
     private void dispatchVisibilityChanged() {
         for (BouncerExpansionCallback callback : mExpansionCallbacks) {
-            callback.onVisibilityChanged(mRoot.getVisibility() == View.VISIBLE);
+            callback.onVisibilityChanged(mContainer.getVisibility() == View.VISIBLE);
         }
     }
 
@@ -601,6 +587,7 @@
         pw.println("  mShowingSoon: " + mShowingSoon);
         pw.println("  mBouncerPromptReason: " + mBouncerPromptReason);
         pw.println("  mIsAnimatingAway: " + mIsAnimatingAway);
+        pw.println("  mInitialized: " + mInitialized);
     }
 
     /** Update keyguard position based on a tapped X coordinate. */
@@ -675,7 +662,10 @@
             mKeyguardBouncerComponentFactory = keyguardBouncerComponentFactory;
         }
 
-        public KeyguardBouncer create(@RootView ViewGroup container,
+        /**
+         * Construct a KeyguardBouncer that will exist in the given container.
+         */
+        public KeyguardBouncer create(ViewGroup container,
                 BouncerExpansionCallback expansionCallback) {
             return new KeyguardBouncer(mContext, mCallback, container,
                     mDismissCallbackRegistry, mFalsingCollector, expansionCallback,
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 7ca8652..732e5f0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -57,8 +57,7 @@
     private int mUserSwitchPreferredY;
 
     /**
-     * Minimum top margin to avoid overlap with status bar, lock icon, or multi-user switcher
-     * avatar.
+     * Minimum top margin to avoid overlap with status bar or multi-user switcher avatar.
      */
     private int mMinTopMargin;
 
@@ -203,7 +202,7 @@
         if (mBypassEnabled) {
             return mUnlockedStackScrollerPadding;
         } else if (mIsSplitShade) {
-            return getClockY(1.0f, mDarkAmount);
+            return getClockY(1.0f, mDarkAmount) + mUserSwitchHeight;
         } else {
             return getClockY(1.0f, mDarkAmount) + mKeyguardStatusHeight;
         }
@@ -213,7 +212,7 @@
         if (mBypassEnabled) {
             return (int) (mUnlockedStackScrollerPadding + mOverStretchAmount);
         } else if (mIsSplitShade) {
-            return Math.max(0, clockYPosition - mSplitShadeTopNotificationsMargin);
+            return clockYPosition - mSplitShadeTopNotificationsMargin + mUserSwitchHeight;
         } else {
             return clockYPosition + mKeyguardStatusHeight;
         }
@@ -223,7 +222,7 @@
         if (mBypassEnabled) {
             return mUnlockedStackScrollerPadding;
         } else if (mIsSplitShade) {
-            return Math.max(mSplitShadeTargetTopMargin, mMinTopMargin);
+            return mSplitShadeTargetTopMargin + mUserSwitchHeight;
         } else {
             return mMinTopMargin + mKeyguardStatusHeight;
         }
@@ -231,7 +230,7 @@
 
     private int getExpandedPreferredClockY() {
         if (mIsSplitShade) {
-            return Math.max(mSplitShadeTargetTopMargin, mMinTopMargin);
+            return mSplitShadeTargetTopMargin;
         } else {
             return mMinTopMargin;
         }
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 434671c..03b1627 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.phone;
 
+import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
 import static android.view.View.GONE;
 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
 
@@ -197,6 +198,7 @@
 import com.android.systemui.statusbar.policy.KeyguardUserSwitcherController;
 import com.android.systemui.statusbar.policy.KeyguardUserSwitcherView;
 import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
+import com.android.systemui.statusbar.window.StatusBarWindowStateController;
 import com.android.systemui.unfold.SysUIUnfoldComponent;
 import com.android.systemui.util.Utils;
 import com.android.systemui.util.settings.SecureSettings;
@@ -732,7 +734,9 @@
             NotificationEntryManager notificationEntryManager,
             CommunalStateController communalStateController,
             KeyguardStateController keyguardStateController,
-            StatusBarStateController statusBarStateController, DozeLog dozeLog,
+            StatusBarStateController statusBarStateController,
+            StatusBarWindowStateController statusBarWindowStateController,
+            DozeLog dozeLog,
             DozeParameters dozeParameters, CommandQueue commandQueue, VibratorHelper vibratorHelper,
             LatencyTracker latencyTracker, PowerManager powerManager,
             AccessibilityManager accessibilityManager, @DisplayId int displayId,
@@ -862,6 +866,7 @@
                 mQs.animateHeaderSlidingOut();
             }
         });
+        statusBarWindowStateController.addListener(this::onStatusBarWindowStateChanged);
         mThemeResId = mView.getContext().getThemeResId();
         mKeyguardBypassController = bypassController;
         mUpdateMonitor = keyguardUpdateMonitor;
@@ -1440,8 +1445,11 @@
             mKeyguardStatusViewController.displayClock(LARGE, shouldAnimateClockChange);
         }
         updateKeyguardStatusViewAlignment(true /* animate */);
-        int userIconHeight = mKeyguardQsUserSwitchController != null
+        int userSwitcherHeight = mKeyguardQsUserSwitchController != null
                 ? mKeyguardQsUserSwitchController.getUserIconHeight() : 0;
+        if (mKeyguardUserSwitcherController != null) {
+            userSwitcherHeight = mKeyguardUserSwitcherController.getHeight();
+        }
         float expandedFraction =
                 mScreenOffAnimationController.shouldExpandNotifications()
                         ? 1.0f : getExpandedFraction();
@@ -1461,7 +1469,7 @@
                 mStatusBarHeaderHeightKeyguard,
                 expandedFraction,
                 mKeyguardStatusViewController.getLockscreenHeight(),
-                userIconHeight,
+                userSwitcherHeight,
                 userSwitcherPreferredY,
                 darkamount, mOverStretchAmount,
                 bypassEnabled, getUnlockedStackScrollerPadding(),
@@ -5006,4 +5014,14 @@
     public PhoneStatusBarView.TouchEventHandler getStatusBarTouchEventHandler() {
         return mStatusBarViewTouchEventHandler;
     }
+
+    private void onStatusBarWindowStateChanged(@StatusBarManager.WindowVisibleState int state) {
+        if (state != WINDOW_STATE_SHOWING
+                && mStatusBarStateController.getState() == StatusBarState.SHADE) {
+            collapsePanel(
+                    false /* animate */,
+                    false /* delayed */,
+                    1.0f /* speedUpFactor */);
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowView.java
index 72f1695..fb0e306 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowView.java
@@ -50,7 +50,7 @@
 import android.widget.FrameLayout;
 
 import com.android.internal.view.FloatingActionMode;
-import com.android.internal.widget.FloatingToolbar;
+import com.android.internal.widget.floatingtoolbar.FloatingToolbar;
 import com.android.systemui.R;
 
 /**
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 81d4bbf..4e2eb6a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
@@ -16,10 +16,7 @@
 
 package com.android.systemui.statusbar.phone;
 
-import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
-
 import android.app.StatusBarManager;
-import android.graphics.RectF;
 import android.hardware.display.AmbientDisplayConfiguration;
 import android.media.AudioManager;
 import android.media.session.MediaSessionLegacyHelper;
@@ -39,24 +36,15 @@
 import com.android.systemui.R;
 import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.dock.DockManager;
-import com.android.systemui.doze.DozeLog;
-import com.android.systemui.shared.plugins.PluginManager;
-import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.DragDownHelper;
 import com.android.systemui.statusbar.LockscreenShadeTransitionController;
-import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationShadeDepthController;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
-import com.android.systemui.statusbar.PulseExpansionHandler;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
-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.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
 import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
-import com.android.systemui.statusbar.policy.KeyguardStateController;
-import com.android.systemui.statusbar.window.StatusBarWindowController;
+import com.android.systemui.statusbar.window.StatusBarWindowStateController;
 import com.android.systemui.tuner.TunerService;
 
 import java.io.FileDescriptor;
@@ -69,27 +57,16 @@
  */
 public class NotificationShadeWindowViewController {
     private static final String TAG = "NotifShadeWindowVC";
-    private final NotificationWakeUpCoordinator mCoordinator;
-    private final PulseExpansionHandler mPulseExpansionHandler;
-    private final DynamicPrivacyController mDynamicPrivacyController;
-    private final KeyguardBypassController mBypassController;
-    private final PluginManager mPluginManager;
     private final FalsingCollector mFalsingCollector;
     private final TunerService mTunerService;
-    private final NotificationLockscreenUserManager mNotificationLockscreenUserManager;
-    private final NotificationEntryManager mNotificationEntryManager;
-    private final KeyguardStateController mKeyguardStateController;
     private final SysuiStatusBarStateController mStatusBarStateController;
-    private final DozeLog mDozeLog;
-    private final DozeParameters mDozeParameters;
-    private final CommandQueue mCommandQueue;
     private final NotificationShadeWindowView mView;
-    private final ShadeController mShadeController;
     private final NotificationShadeDepthController mDepthController;
     private final NotificationStackScrollLayoutController mNotificationStackScrollLayoutController;
     private final LockscreenShadeTransitionController mLockscreenShadeTransitionController;
     private final LockIconViewController mLockIconViewController;
     private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
+    private final StatusBarWindowStateController mStatusBarWindowStateController;
 
     private GestureDetector mGestureDetector;
     private View mBrightnessMirror;
@@ -97,7 +74,7 @@
     private boolean mTouchCancelled;
     private boolean mExpandAnimationRunning;
     private NotificationStackScrollLayout mStackScrollLayout;
-    private PhoneStatusBarView mStatusBarView;
+    private PhoneStatusBarViewController mStatusBarViewController;
     private StatusBar mService;
     private NotificationShadeWindowController mNotificationShadeWindowController;
     private DragDownHelper mDragDownHelper;
@@ -107,64 +84,36 @@
     private final DockManager mDockManager;
     private final NotificationPanelViewController mNotificationPanelViewController;
     private final PanelExpansionStateManager mPanelExpansionStateManager;
-    private final StatusBarWindowController mStatusBarWindowController;
 
-    // Used for determining view / touch intersection
-    private int[] mTempLocation = new int[2];
-    private RectF mTempRect = new RectF();
     private boolean mIsTrackingBarGesture = false;
 
     @Inject
     public NotificationShadeWindowViewController(
-            NotificationWakeUpCoordinator coordinator,
-            PulseExpansionHandler pulseExpansionHandler,
-            DynamicPrivacyController dynamicPrivacyController,
-            KeyguardBypassController bypassController,
             LockscreenShadeTransitionController transitionController,
             FalsingCollector falsingCollector,
-            PluginManager pluginManager,
             TunerService tunerService,
-            NotificationLockscreenUserManager notificationLockscreenUserManager,
-            NotificationEntryManager notificationEntryManager,
-            KeyguardStateController keyguardStateController,
             SysuiStatusBarStateController statusBarStateController,
-            DozeLog dozeLog,
-            DozeParameters dozeParameters,
-            CommandQueue commandQueue,
-            ShadeController shadeController,
             DockManager dockManager,
             NotificationShadeDepthController depthController,
             NotificationShadeWindowView notificationShadeWindowView,
             NotificationPanelViewController notificationPanelViewController,
             PanelExpansionStateManager panelExpansionStateManager,
-            StatusBarWindowController statusBarWindowController,
             NotificationStackScrollLayoutController notificationStackScrollLayoutController,
             StatusBarKeyguardViewManager statusBarKeyguardViewManager,
+            StatusBarWindowStateController statusBarWindowStateController,
             LockIconViewController lockIconViewController) {
-        mCoordinator = coordinator;
-        mPulseExpansionHandler = pulseExpansionHandler;
-        mDynamicPrivacyController = dynamicPrivacyController;
-        mBypassController = bypassController;
         mLockscreenShadeTransitionController = transitionController;
         mFalsingCollector = falsingCollector;
-        mPluginManager = pluginManager;
         mTunerService = tunerService;
-        mNotificationLockscreenUserManager = notificationLockscreenUserManager;
-        mNotificationEntryManager = notificationEntryManager;
-        mKeyguardStateController = keyguardStateController;
         mStatusBarStateController = statusBarStateController;
-        mDozeLog = dozeLog;
-        mDozeParameters = dozeParameters;
-        mCommandQueue = commandQueue;
         mView = notificationShadeWindowView;
-        mShadeController = shadeController;
         mDockManager = dockManager;
         mNotificationPanelViewController = notificationPanelViewController;
         mPanelExpansionStateManager = panelExpansionStateManager;
         mDepthController = depthController;
-        mStatusBarWindowController = statusBarWindowController;
         mNotificationStackScrollLayoutController = notificationStackScrollLayoutController;
         mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
+        mStatusBarWindowStateController = statusBarWindowStateController;
         mLockIconViewController = lockIconViewController;
 
         // This view is not part of the newly inflated expanded status bar.
@@ -225,7 +174,7 @@
         mView.setInteractionEventHandler(new NotificationShadeWindowView.InteractionEventHandler() {
             @Override
             public Boolean handleDispatchTouchEvent(MotionEvent ev) {
-                if (mStatusBarView == null) {
+                if (mStatusBarViewController == null) { // Fix for b/192490822
                     Log.w(TAG, "Ignoring touch while statusBarView not yet set.");
                     return false;
                 }
@@ -247,11 +196,11 @@
                 }
 
                 if (isDown) {
-                    setTouchActive(true);
+                    mTouchActive = true;
                     mTouchCancelled = false;
                 } else if (ev.getActionMasked() == MotionEvent.ACTION_UP
                         || ev.getActionMasked() == MotionEvent.ACTION_CANCEL) {
-                    setTouchActive(false);
+                    mTouchActive = false;
                 }
                 if (mTouchCancelled || mExpandAnimationRunning) {
                     return false;
@@ -293,27 +242,27 @@
                     expandingBelowNotch = true;
                 }
                 if (expandingBelowNotch) {
-                    return mStatusBarView.dispatchTouchEvent(ev);
+                    return mStatusBarViewController.sendTouchToView(ev);
                 }
 
                 if (!mIsTrackingBarGesture && isDown
                         && mNotificationPanelViewController.isFullyCollapsed()) {
                     float x = ev.getRawX();
                     float y = ev.getRawY();
-                    if (isIntersecting(mStatusBarView, x, y)) {
-                        if (mService.isSameStatusBarState(WINDOW_STATE_SHOWING)) {
+                    if (mStatusBarViewController.touchIsWithinView(x, y)) {
+                        if (mStatusBarWindowStateController.windowIsShowing()) {
                             mIsTrackingBarGesture = true;
-                            return mStatusBarView.dispatchTouchEvent(ev);
+                            return mStatusBarViewController.sendTouchToView(ev);
                         } else { // it's hidden or hiding, don't send to notification shade.
                             return true;
                         }
                     }
                 } else if (mIsTrackingBarGesture) {
-                    final boolean sendToNotification = mStatusBarView.dispatchTouchEvent(ev);
+                    final boolean sendToStatusBar = mStatusBarViewController.sendTouchToView(ev);
                     if (isUp || isCancel) {
                         mIsTrackingBarGesture = false;
                     }
-                    return sendToNotification;
+                    return sendToStatusBar;
                 }
 
                 return null;
@@ -458,10 +407,6 @@
         return mView;
     }
 
-    public void setTouchActive(boolean touchActive) {
-        mTouchActive = touchActive;
-    }
-
     public void cancelCurrentTouch() {
         if (mTouchActive) {
             final long now = SystemClock.uptimeMillis();
@@ -496,8 +441,8 @@
         }
     }
 
-    public void setStatusBarView(PhoneStatusBarView statusBarView) {
-        mStatusBarView = statusBarView;
+    public void setStatusBarViewController(PhoneStatusBarViewController statusBarViewController) {
+        mStatusBarViewController = statusBarViewController;
     }
 
     public void setService(StatusBar statusBar, NotificationShadeWindowController controller) {
@@ -509,11 +454,4 @@
     void setDragDownHelper(DragDownHelper dragDownHelper) {
         mDragDownHelper = dragDownHelper;
     }
-
-    private boolean isIntersecting(View view, float x, float y) {
-        mTempLocation = view.getLocationOnScreen();
-        mTempRect.set(mTempLocation[0], mTempLocation[1], mTempLocation[0] + view.getWidth(),
-                mTempLocation[1] + view.getHeight());
-        return mTempRect.contains(x, y);
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
index b9386bd..1cb19ab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
@@ -17,6 +17,7 @@
 
 import android.content.res.Configuration
 import android.graphics.Point
+import android.view.MotionEvent
 import android.view.View
 import android.view.ViewGroup
 import android.view.ViewTreeObserver
@@ -92,6 +93,30 @@
         mView.importantForAccessibility = mode
     }
 
+    /**
+     * Sends a touch event to the status bar view.
+     *
+     * This is required in certain cases because the status bar view is in a separate window from
+     * the rest of SystemUI, and other windows may decide that their touch should instead be treated
+     * as a status bar window touch.
+     */
+    fun sendTouchToView(ev: MotionEvent): Boolean {
+        return mView.dispatchTouchEvent(ev)
+    }
+
+    /**
+     * Returns true if the given (x, y) point (in screen coordinates) is within the status bar
+     * view's range and false otherwise.
+     */
+    fun touchIsWithinView(x: Float, y: Float): Boolean {
+        val left = mView.locationOnScreen[0]
+        val top = mView.locationOnScreen[1]
+        return left <= x &&
+                x <= left + mView.width &&
+                top <= y &&
+                y <= top + mView.height
+    }
+
     class StatusBarViewsCenterProvider : UnfoldMoveFromCenterAnimator.ViewCenterProvider {
         override fun getViewCenter(view: View, outPoint: Point) =
             when (view.id) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeController.java
index 2d41e5e..24bb7f2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeController.java
@@ -55,6 +55,9 @@
      */
     boolean closeShadeIfOpen();
 
+    /** Returns whether the shade is currently open or opening. */
+    boolean isShadeOpen();
+
     /**
      * Add a runnable for NotificationPanelView to post when the panel is expanded.
      *
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 b4fed2b..f8b0535 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeControllerImpl.java
@@ -148,6 +148,13 @@
     }
 
     @Override
+    public boolean isShadeOpen() {
+        NotificationPanelViewController controller =
+                getNotificationPanelViewController();
+        return controller.isExpanding() || controller.isFullyExpanded();
+    }
+
+    @Override
     public void postOnShadeExpanded(Runnable executable) {
         getNotificationPanelViewController().addOnGlobalLayoutListener(
                 new ViewTreeObserver.OnGlobalLayoutListener() {
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 07914cf..1cc5e12 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -70,6 +70,7 @@
 import android.content.res.Configuration;
 import android.graphics.Point;
 import android.graphics.PointF;
+import android.hardware.devicestate.DeviceStateManager;
 import android.metrics.LogMaker;
 import android.net.Uri;
 import android.os.Bundle;
@@ -116,6 +117,7 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.colorextraction.ColorExtractor;
+import com.android.internal.jank.InteractionJankMonitor;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.UiEvent;
 import com.android.internal.logging.UiEventLogger;
@@ -232,6 +234,7 @@
 import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
 import com.android.systemui.statusbar.window.StatusBarWindowController;
+import com.android.systemui.statusbar.window.StatusBarWindowStateController;
 import com.android.systemui.util.DumpUtilsKt;
 import com.android.systemui.util.WallpaperController;
 import com.android.systemui.util.concurrency.DelayableExecutor;
@@ -337,15 +340,9 @@
     private final LockscreenShadeTransitionController mLockscreenShadeTransitionController;
     private StatusBarCommandQueueCallbacks mCommandQueueCallbacks;
 
-    void setWindowState(int state) {
-        mStatusBarWindowState =  state;
-        mStatusBarWindowHidden = state == WINDOW_STATE_HIDDEN;
-        mStatusBarHideIconsForBouncerManager.setStatusBarWindowHidden(mStatusBarWindowHidden);
-        if (mStatusBarView != null) {
-            // Should #updateHideIconsForBouncer always be called, regardless of whether we have a
-            //   status bar view? If so, we can make #updateHideIconsForBouncer private.
-            mStatusBarHideIconsForBouncerManager.updateHideIconsForBouncer(/* animate= */ false);
-        }
+    void onStatusBarWindowStateChanged(@WindowVisibleState int state) {
+        updateBubblesVisibility();
+        mStatusBarWindowState = state;
     }
 
     void acquireGestureWakeLock(long time) {
@@ -464,7 +461,7 @@
     private PhoneStatusBarViewController mPhoneStatusBarViewController;
     private PhoneStatusBarTransitions mStatusBarTransitions;
     private AuthRippleController mAuthRippleController;
-    private int mStatusBarWindowState = WINDOW_STATE_SHOWING;
+    @WindowVisibleState private int mStatusBarWindowState = WINDOW_STATE_SHOWING;
     protected NotificationShadeWindowController mNotificationShadeWindowController;
     private final StatusBarWindowController mStatusBarWindowController;
     private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@@ -677,6 +674,8 @@
     private final ColorExtractor.OnColorsChangedListener mOnColorsChangedListener =
             (extractor, which) -> updateTheme();
 
+    private final InteractionJankMonitor mJankMonitor;
+
 
     /**
      * Public constructor for StatusBar.
@@ -692,6 +691,7 @@
             LightBarController lightBarController,
             AutoHideController autoHideController,
             StatusBarWindowController statusBarWindowController,
+            StatusBarWindowStateController statusBarWindowStateController,
             KeyguardUpdateMonitor keyguardUpdateMonitor,
             StatusBarSignalPolicy statusBarSignalPolicy,
             PulseExpansionHandler pulseExpansionHandler,
@@ -779,7 +779,9 @@
             WallpaperManager wallpaperManager,
             Optional<StartingSurface> startingSurfaceOptional,
             ActivityLaunchAnimator activityLaunchAnimator,
-            NotifPipelineFlags notifPipelineFlags) {
+            NotifPipelineFlags notifPipelineFlags,
+            InteractionJankMonitor jankMonitor,
+            DeviceStateManager deviceStateManager) {
         super(context);
         mNotificationsController = notificationsController;
         mFragmentService = fragmentService;
@@ -867,11 +869,13 @@
         mMainExecutor = delayableExecutor;
         mMessageRouter = messageRouter;
         mWallpaperManager = wallpaperManager;
+        mJankMonitor = jankMonitor;
 
         mLockscreenShadeTransitionController = lockscreenShadeTransitionController;
         mStartingSurfaceOptional = startingSurfaceOptional;
         mNotifPipelineFlags = notifPipelineFlags;
         lockscreenShadeTransitionController.setStatusbar(this);
+        statusBarWindowStateController.addListener(this::onStatusBarWindowStateChanged);
 
         mScreenOffAnimationController = screenOffAnimationController;
 
@@ -900,6 +904,9 @@
                 data -> mCommandQueueCallbacks.animateExpandSettingsPanel(data.mSubpanel));
         mMessageRouter.subscribeTo(MSG_LAUNCH_TRANSITION_TIMEOUT,
                 id -> onLaunchTransitionTimeout());
+
+        deviceStateManager.registerCallback(mMainExecutor,
+                new FoldStateListener(mContext, this::onFoldedStateChanged));
     }
 
     @Override
@@ -1098,6 +1105,27 @@
                                 requestTopUi, componentTag))));
     }
 
+    private void onFoldedStateChanged(boolean isFolded, boolean willGoToSleep) {
+        // Folded state changes are followed by a screen off event.
+        // By default turning off the screen also closes the shade.
+        // We want to make sure that the shade status is kept after
+        // folding/unfolding.
+        boolean isShadeOpen = mShadeController.isShadeOpen();
+        boolean leaveOpen = isShadeOpen && !willGoToSleep;
+        if (DEBUG) {
+            Log.d(TAG, String.format(
+                    "#onFoldedStateChanged(): "
+                            + "isFolded=%s, "
+                            + "willGoToSleep=%s, "
+                            + "isShadeOpen=%s, "
+                            + "leaveOpen=%s",
+                    isFolded, willGoToSleep, isShadeOpen, leaveOpen));
+        }
+        if (leaveOpen) {
+            mStatusBarStateController.setLeaveOpenOnKeyguardHide(true);
+        }
+    }
+
     // ================================================================================
     // Constructing the view
     // ================================================================================
@@ -1133,7 +1161,8 @@
                     mStatusBarView = statusBarView;
                     mPhoneStatusBarViewController = statusBarViewController;
                     mStatusBarTransitions = statusBarTransitions;
-                    mNotificationShadeWindowViewController.setStatusBarView(mStatusBarView);
+                    mNotificationShadeWindowViewController
+                            .setStatusBarViewController(mPhoneStatusBarViewController);
                     // Ensure we re-propagate panel expansion values to the panel controller and
                     // any listeners it may have, such as PanelBar. This will also ensure we
                     // re-display the notification panel if necessary (for example, if
@@ -1387,7 +1416,8 @@
         mNotificationAnimationProvider = new NotificationLaunchAnimatorControllerProvider(
                 mNotificationShadeWindowViewController,
                 mStackScrollerController.getNotificationListContainer(),
-                mHeadsUpManager
+                mHeadsUpManager,
+                mJankMonitor
         );
 
         // TODO: inject this.
@@ -2105,10 +2135,6 @@
         }
     }
 
-    boolean isSameStatusBarState(int state) {
-        return mStatusBarWindowState == state;
-    }
-
     public GestureRecorder getGestureRecorder() {
         return mGestureRec;
     }
@@ -3162,7 +3188,7 @@
         boolean wakeAndUnlock = mBiometricUnlockController.getMode()
                 == BiometricUnlockController.MODE_WAKE_AND_UNLOCK;
         boolean animate = (!mDozing && mDozeServiceHost.shouldAnimateWakeup() && !wakeAndUnlock)
-                || (mDozing && mDozeServiceHost.shouldAnimateScreenOff()
+                || (mDozing && mDozeParameters.shouldControlScreenOff()
                 && visibleNotOccludedOrWillBe);
 
         mNotificationPanelViewController.setDozing(mDozing, animate, mWakeUpTouchLocation);
@@ -3586,7 +3612,7 @@
 
     final ScreenLifecycle.Observer mScreenObserver = new ScreenLifecycle.Observer() {
         @Override
-        public void onScreenTurningOn() {
+        public void onScreenTurningOn(Runnable onDrawn) {
             mFalsingCollector.onScreenTurningOn();
             mNotificationPanelViewController.onScreenTurningOn();
         }
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 b391de3..51f2e67 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacks.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacks.java
@@ -16,8 +16,6 @@
 
 package com.android.systemui.statusbar.phone;
 
-import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
-import static android.app.StatusBarManager.windowStateToString;
 import static android.view.InsetsState.ITYPE_STATUS_BAR;
 import static android.view.InsetsState.containsType;
 
@@ -58,7 +56,6 @@
 import com.android.systemui.qs.QSPanelController;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.DisableFlagsLogger;
-import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.VibratorHelper;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
@@ -515,30 +512,6 @@
     }
 
     @Override
-    public void setWindowState(
-            int displayId, @StatusBarManager.WindowType int window,
-            @StatusBarManager.WindowVisibleState int state) {
-        if (displayId != mDisplayId) {
-            return;
-        }
-        boolean showing = state == WINDOW_STATE_SHOWING;
-        if (mNotificationShadeWindowView != null
-                && window == StatusBarManager.WINDOW_STATUS_BAR
-                && !mStatusBar.isSameStatusBarState(state)) {
-            mStatusBar.setWindowState(state);
-            if (StatusBar.DEBUG_WINDOW_STATE) {
-                Log.d(StatusBar.TAG, "Status bar " + windowStateToString(state));
-            }
-            if (!showing && mStatusBarStateController.getState() == StatusBarState.SHADE) {
-                mNotificationPanelViewController.collapsePanel(
-                            false /* animate */, false /* delayed */, 1.0f /* speedUpFactor */);
-            }
-        }
-
-        mStatusBar.updateBubblesVisibility();
-    }
-
-    @Override
     public void showAssistDisclosure() {
         mAssistManager.showDisclosure();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHideIconsForBouncerManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHideIconsForBouncerManager.kt
index d2181d0..17516e0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHideIconsForBouncerManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHideIconsForBouncerManager.kt
@@ -1,10 +1,12 @@
 package com.android.systemui.statusbar.phone
 
+import android.app.StatusBarManager
 import com.android.systemui.Dumpable
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.statusbar.CommandQueue
+import com.android.systemui.statusbar.window.StatusBarWindowStateController
 import com.android.systemui.util.concurrency.DelayableExecutor
 import java.io.FileDescriptor
 import java.io.PrintWriter
@@ -25,6 +27,7 @@
 class StatusBarHideIconsForBouncerManager @Inject constructor(
     private val commandQueue: CommandQueue,
     @Main private val mainExecutor: DelayableExecutor,
+    statusBarWindowStateController: StatusBarWindowStateController,
     dumpManager: DumpManager
 ) : Dumpable {
     // State variables set by external classes.
@@ -42,6 +45,9 @@
 
     init {
         dumpManager.registerDumpable(this)
+        statusBarWindowStateController.addListener {
+                state -> setStatusBarStateAndTriggerUpdate(state)
+        }
     }
 
     /** Returns true if the status bar icons should be hidden in the bouncer. */
@@ -49,8 +55,9 @@
         return hideIconsForBouncer || wereIconsJustHidden
     }
 
-    fun setStatusBarWindowHidden(statusBarWindowHidden: Boolean) {
-        this.statusBarWindowHidden = statusBarWindowHidden
+    private fun setStatusBarStateAndTriggerUpdate(@StatusBarManager.WindowVisibleState state: Int) {
+        statusBarWindowHidden = state == StatusBarManager.WINDOW_STATE_HIDDEN
+        updateHideIconsForBouncer(animate = false)
     }
 
     fun setDisplayId(displayId: Int) {
@@ -87,7 +94,7 @@
      * Updates whether the status bar icons should be hidden in the bouncer. May trigger
      * [commandQueue.recomputeDisableFlags] if the icon visibility status changes.
      */
-    fun updateHideIconsForBouncer(animate: Boolean) {
+    private fun updateHideIconsForBouncer(animate: Boolean) {
         val hideBecauseApp =
             topAppHidesStatusBar &&
                     isOccluded &&
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 875b7e5..316e682 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -51,7 +51,6 @@
 import com.android.systemui.DejankUtils;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dock.DockManager;
-import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.navigationbar.NavigationBarView;
 import com.android.systemui.navigationbar.NavigationModeController;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -87,7 +86,7 @@
 public class StatusBarKeyguardViewManager implements RemoteInputController.Callback,
         StatusBarStateController.StateListener, ConfigurationController.ConfigurationListener,
         PanelExpansionListener, NavigationModeController.ModeChangedListener,
-        KeyguardViewController, WakefulnessLifecycle.Observer {
+        KeyguardViewController {
 
     // When hiding the Keyguard with timing supplied from WindowManager, better be early than late.
     private static final long HIDE_TIMING_CORRECTION_MS = - 16 * 3;
@@ -392,17 +391,13 @@
         } else {
             mStatusBar.showKeyguard();
             if (hideBouncerWhenShowing) {
-                hideBouncer(shouldDestroyViewOnReset() /* destroyView */);
+                hideBouncer(false /* destroyView */);
                 mBouncer.prepare();
             }
         }
         updateStates();
     }
 
-    protected boolean shouldDestroyViewOnReset() {
-        return false;
-    }
-
     /**
      * If applicable, shows the alternate authentication bouncer. Else, shows the input
      * (pin/password/pattern) bouncer.
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 fc661b9..0ba7134 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
@@ -9,6 +9,9 @@
 import android.provider.Settings
 import android.view.Surface
 import android.view.View
+import com.android.internal.jank.InteractionJankMonitor
+import com.android.internal.jank.InteractionJankMonitor.CUJ_SCREEN_OFF
+import com.android.internal.jank.InteractionJankMonitor.CUJ_SCREEN_OFF_SHOW_AOD
 import com.android.systemui.animation.Interpolators
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.keyguard.KeyguardViewMediator
@@ -50,7 +53,8 @@
     private val keyguardViewMediatorLazy: dagger.Lazy<KeyguardViewMediator>,
     private val keyguardStateController: KeyguardStateController,
     private val dozeParameters: dagger.Lazy<DozeParameters>,
-    private val globalSettings: GlobalSettings
+    private val globalSettings: GlobalSettings,
+    private val interactionJankMonitor: InteractionJankMonitor
 ) : WakefulnessLifecycle.Observer, ScreenOffAnimation {
     private val handler = Handler()
 
@@ -78,17 +82,28 @@
             sendUnlockedScreenOffProgressUpdate(
                     1f - (it.animatedFraction as Float),
                     1f - (it.animatedValue as Float))
+            if (lightRevealScrim.isScrimAlmostOccludes &&
+                    interactionJankMonitor.isInstrumenting(CUJ_SCREEN_OFF)) {
+                // ends the instrument when the scrim almost occludes the screen.
+                // because the following janky frames might not be perceptible.
+                interactionJankMonitor.end(CUJ_SCREEN_OFF)
+            }
         }
         addListener(object : AnimatorListenerAdapter() {
             override fun onAnimationCancel(animation: Animator?) {
                 lightRevealScrim.revealAmount = 1f
                 lightRevealAnimationPlaying = false
                 sendUnlockedScreenOffProgressUpdate(0f, 0f)
+                interactionJankMonitor.cancel(CUJ_SCREEN_OFF)
             }
 
             override fun onAnimationEnd(animation: Animator?) {
                 lightRevealAnimationPlaying = false
             }
+
+            override fun onAnimationStart(animation: Animator?) {
+                interactionJankMonitor.begin(statusBar.notificationShadeWindowView, CUJ_SCREEN_OFF)
+            }
         })
     }
 
@@ -163,6 +178,16 @@
                         decidedToAnimateGoingToSleep = null
                         // We need to unset the listener. These are persistent for future animators
                         keyguardView.animate().setListener(null)
+                        interactionJankMonitor.end(CUJ_SCREEN_OFF_SHOW_AOD)
+                    }
+
+                    override fun onAnimationCancel(animation: Animator?) {
+                        interactionJankMonitor.cancel(CUJ_SCREEN_OFF_SHOW_AOD)
+                    }
+
+                    override fun onAnimationStart(animation: Animator?) {
+                        interactionJankMonitor.begin(
+                                statusBar.notificationShadeWindowView, CUJ_SCREEN_OFF_SHOW_AOD)
                     }
                 })
                 .start()
@@ -229,10 +254,6 @@
             return false
         }
 
-        if (!dozeParameters.get().canControlUnlockedScreenOff()) {
-            return false
-        }
-
         // If animations are disabled system-wide, don't play this one either.
         if (Settings.Global.getString(
                 context.contentResolver, Settings.Global.ANIMATOR_DURATION_SCALE) == "0") {
@@ -248,10 +269,10 @@
         // already expanded and showing notifications/QS, the animation looks really messy. For now,
         // disable it if the notification panel is not fully collapsed.
         if ((!this::statusBar.isInitialized ||
-                !statusBar.notificationPanelViewController.isFullyCollapsed)
+                !statusBar.notificationPanelViewController.isFullyCollapsed) &&
                 // Status bar might be expanded because we have started
                 // playing the animation already
-                && !isAnimationPlaying()
+                !isAnimationPlaying()
         ) {
             return false
         }
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 f93a8dc..977fe9c 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
@@ -20,10 +20,12 @@
 
 import android.app.WallpaperManager;
 import android.content.Context;
+import android.hardware.devicestate.DeviceStateManager;
 import android.os.Handler;
 import android.os.PowerManager;
 import android.util.DisplayMetrics;
 
+import com.android.internal.jank.InteractionJankMonitor;
 import com.android.internal.logging.MetricsLogger;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.ViewMediatorCallback;
@@ -105,6 +107,7 @@
 import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
 import com.android.systemui.statusbar.window.StatusBarWindowController;
+import com.android.systemui.statusbar.window.StatusBarWindowStateController;
 import com.android.systemui.util.WallpaperController;
 import com.android.systemui.util.concurrency.DelayableExecutor;
 import com.android.systemui.util.concurrency.MessageRouter;
@@ -140,6 +143,7 @@
             LightBarController lightBarController,
             AutoHideController autoHideController,
             StatusBarWindowController statusBarWindowController,
+            StatusBarWindowStateController statusBarWindowStateController,
             KeyguardUpdateMonitor keyguardUpdateMonitor,
             StatusBarSignalPolicy statusBarSignalPolicy,
             PulseExpansionHandler pulseExpansionHandler,
@@ -227,7 +231,9 @@
             WallpaperManager wallpaperManager,
             Optional<StartingSurface> startingSurfaceOptional,
             ActivityLaunchAnimator activityLaunchAnimator,
-            NotifPipelineFlags notifPipelineFlags) {
+            NotifPipelineFlags notifPipelineFlags,
+            InteractionJankMonitor jankMonitor,
+            DeviceStateManager deviceStateManager) {
         return new StatusBar(
                 context,
                 notificationsController,
@@ -235,6 +241,7 @@
                 lightBarController,
                 autoHideController,
                 statusBarWindowController,
+                statusBarWindowStateController,
                 keyguardUpdateMonitor,
                 statusBarSignalPolicy,
                 pulseExpansionHandler,
@@ -321,7 +328,9 @@
                 wallpaperManager,
                 startingSurfaceOptional,
                 activityLaunchAnimator,
-                notifPipelineFlags
+                notifPipelineFlags,
+                jankMonitor,
+                deviceStateManager
         );
     }
 }
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 2dfcc98..c1f63b8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
@@ -171,6 +171,8 @@
         if (mShowing == showing && mOccluded == occluded) return;
         mShowing = showing;
         mOccluded = occluded;
+        Trace.instantForTrack(Trace.TRACE_TAG_APP, "UI Events",
+                "Keyguard showing: " + showing + " occluded: " + occluded);
         notifyKeyguardChanged();
 
         // Update the dismiss amount to the full 0f/1f if we explicitly show or hide the keyguard.
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 ffa7963..04a6a11 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java
@@ -248,6 +248,10 @@
         return mUserSwitcherController.isSimpleUserSwitcher();
     }
 
+    public int getHeight() {
+        return mListView.getHeight();
+    }
+
     /**
      * @param animate if the transition should be animated
      * @return true if the switcher state changed
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 cd8894c..850a4b4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherListView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherListView.java
@@ -97,9 +97,12 @@
             } else {
                 // Update clickable state immediately so that the menu feels more responsive
                 userItemViews[i].setClickable(open);
-                // Before running the animation, ensure visibility is set correctly
-                userItemViews[i].updateVisibilities(animate || open /* showItem */,
-                        true /* showTextName */, false /* animate */);
+                // when opening we need to make views visible beforehand so they can be animated
+                if (open) {
+                    userItemViews[i].updateVisibilities(true /* showItem */,
+                            true /* showTextName */, false /* animate */);
+                }
+
             }
         }
 
@@ -117,6 +120,13 @@
                         setClipChildren(true);
                         setClipToPadding(true);
                         mAnimating = false;
+                        if (!open) {
+                            // after closing we hide children so that height of this view is correct
+                            for (int i = 1; i < userItemViews.length; i++) {
+                                userItemViews[i].updateVisibilities(false /* showItem */,
+                                        true /* showTextName */, false /* animate */);
+                            }
+                        }
                     });
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
index 8e8a33f..3831857 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.statusbar.policy;
 
+import static android.app.AppOpsManager.OP_COARSE_LOCATION;
+import static android.app.AppOpsManager.OP_FINE_LOCATION;
 import static android.app.AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION;
 
 import static com.android.settingslib.Utils.updateLocationEnabled;
@@ -30,11 +32,13 @@
 import android.os.Message;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.provider.DeviceConfig;
 import android.provider.Settings;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.VisibleForTesting;
 
+import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
 import com.android.systemui.BootCompleteCache;
 import com.android.systemui.appops.AppOpItem;
 import com.android.systemui.appops.AppOpsController;
@@ -43,6 +47,7 @@
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.settings.UserTracker;
+import com.android.systemui.util.DeviceConfigProxy;
 import com.android.systemui.util.Utils;
 
 import java.util.ArrayList;
@@ -59,30 +64,47 @@
 
     private final Context mContext;
     private final AppOpsController mAppOpsController;
+    private final DeviceConfigProxy mDeviceConfigProxy;
     private final BootCompleteCache mBootCompleteCache;
     private final UserTracker mUserTracker;
     private final H mHandler;
 
 
     private boolean mAreActiveLocationRequests;
+    private boolean mShouldDisplayAllAccesses;
 
     @Inject
     public LocationControllerImpl(Context context, AppOpsController appOpsController,
+            DeviceConfigProxy deviceConfigProxy,
             @Main Looper mainLooper, @Background Handler backgroundHandler,
             BroadcastDispatcher broadcastDispatcher, BootCompleteCache bootCompleteCache,
             UserTracker userTracker) {
         mContext = context;
         mAppOpsController = appOpsController;
+        mDeviceConfigProxy = deviceConfigProxy;
         mBootCompleteCache = bootCompleteCache;
         mHandler = new H(mainLooper);
         mUserTracker = userTracker;
+        mShouldDisplayAllAccesses = getDeviceConfigSetting();
+
+        // Register to listen for changes in DeviceConfig settings.
+        mDeviceConfigProxy.addOnPropertiesChangedListener(
+                DeviceConfig.NAMESPACE_PRIVACY,
+                backgroundHandler::post,
+                properties -> {
+                    mShouldDisplayAllAccesses = getDeviceConfigSetting();
+                    updateActiveLocationRequests();
+                });
 
         // Register to listen for changes in location settings.
         IntentFilter filter = new IntentFilter();
         filter.addAction(LocationManager.MODE_CHANGED_ACTION);
         broadcastDispatcher.registerReceiverWithHandler(this, filter, mHandler, UserHandle.ALL);
 
-        mAppOpsController.addCallback(new int[]{OP_MONITOR_HIGH_POWER_LOCATION}, this);
+        // Listen to all accesses and filter the ones interested in based on flags.
+        mAppOpsController.addCallback(
+                new int[]{OP_COARSE_LOCATION, OP_FINE_LOCATION, OP_MONITOR_HIGH_POWER_LOCATION},
+                this);
 
         // Examine the current location state and initialize the status view.
         backgroundHandler.post(this::updateActiveLocationRequests);
@@ -154,6 +176,11 @@
                 UserHandle.of(userId));
     }
 
+    private boolean getDeviceConfigSetting() {
+        return mDeviceConfigProxy.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
+                SystemUiDeviceConfigFlags.PROPERTY_LOCATION_INDICATORS_SMALL_ENABLED, false);
+    }
+
     /**
      * Returns true if there currently exist active high power location requests.
      */
@@ -171,10 +198,37 @@
         return false;
     }
 
-    // Reads the active location requests and updates the status view if necessary.
+    /**
+     * Returns true if there currently exist active location requests.
+     */
+    @VisibleForTesting
+    protected boolean areActiveLocationRequests() {
+        if (!mShouldDisplayAllAccesses) {
+            return false;
+        }
+        List<AppOpItem> appOpsItems = mAppOpsController.getActiveAppOps();
+
+        final int numItems = appOpsItems.size();
+        for (int i = 0; i < numItems; i++) {
+            if (appOpsItems.get(i).getCode() == OP_FINE_LOCATION
+                    || appOpsItems.get(i).getCode() == OP_COARSE_LOCATION) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    // Reads the active location requests from either OP_MONITOR_HIGH_POWER_LOCATION,
+    // OP_FINE_LOCATION, or OP_COARSE_LOCATION and updates the status view if necessary.
     private void updateActiveLocationRequests() {
         boolean hadActiveLocationRequests = mAreActiveLocationRequests;
-        mAreActiveLocationRequests = areActiveHighPowerLocationRequests();
+        if (mShouldDisplayAllAccesses) {
+            mAreActiveLocationRequests =
+                    areActiveHighPowerLocationRequests() || areActiveLocationRequests();
+        } else {
+            mAreActiveLocationRequests = areActiveHighPowerLocationRequests();
+        }
         if (mAreActiveLocationRequests != hadActiveLocationRequests) {
             mHandler.sendEmptyMessage(H.MSG_LOCATION_ACTIVE_CHANGED);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockController.java
index f258fb1..1158324 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockController.java
@@ -23,6 +23,7 @@
     int getRotationLockOrientation();
     boolean isRotationLockAffordanceVisible();
     boolean isRotationLocked();
+    boolean isCameraRotationEnabled();
     void setRotationLocked(boolean locked);
     void setRotationLockedAtAngle(boolean locked, int rotation);
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java
index 67f5364..3143a47 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java
@@ -18,6 +18,9 @@
 
 import static com.android.systemui.statusbar.policy.dagger.StatusBarPolicyModule.DEVICE_STATE_ROTATION_LOCK_DEFAULTS;
 
+import android.Manifest;
+import android.content.Context;
+import android.content.pm.PackageManager;
 import android.os.UserHandle;
 
 import androidx.annotation.NonNull;
@@ -34,6 +37,7 @@
 /** Platform implementation of the rotation lock controller. **/
 @SysUISingleton
 public final class RotationLockControllerImpl implements RotationLockController {
+
     private final CopyOnWriteArrayList<RotationLockControllerCallback> mCallbacks =
             new CopyOnWriteArrayList<>();
 
@@ -86,11 +90,15 @@
         return mRotationPolicy.isRotationLocked();
     }
 
+    public boolean isCameraRotationEnabled() {
+        return mRotationPolicy.isCameraRotationEnabled();
+    }
+
     public void setRotationLocked(boolean locked) {
         mRotationPolicy.setRotationLock(locked);
     }
 
-    public void setRotationLockedAtAngle(boolean locked, int rotation){
+    public void setRotationLockedAtAngle(boolean locked, int rotation) {
         mRotationPolicy.setRotationLockAtAngle(locked, rotation);
     }
 
@@ -121,4 +129,11 @@
         callback.onRotationLockStateChanged(mRotationPolicy.isRotationLocked(),
                 mRotationPolicy.isRotationLockToggleVisible());
     }
+
+    public static boolean hasSufficientPermission(Context context) {
+        final PackageManager packageManager = context.getPackageManager();
+        final String rotationPackage = packageManager.getRotationResolverPackageName();
+        return rotationPackage != null && packageManager.checkPermission(
+                Manifest.permission.CAMERA, rotationPackage) == PackageManager.PERMISSION_GRANTED;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowStateController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowStateController.kt
new file mode 100644
index 0000000..3a14914
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowStateController.kt
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.window
+
+import android.app.StatusBarManager
+import android.app.StatusBarManager.WindowVisibleState
+import android.app.StatusBarManager.WINDOW_STATE_SHOWING
+import android.app.StatusBarManager.WINDOW_STATUS_BAR
+import android.app.StatusBarManager.windowStateToString
+import android.util.Log
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.DisplayId
+import com.android.systemui.statusbar.CommandQueue
+import com.android.systemui.statusbar.phone.StatusBar
+import javax.inject.Inject
+
+/**
+ * A centralized class maintaining the state of the status bar window.
+ *
+ * Classes that want to get updates about the status bar window state should subscribe to this class
+ * via [addListener] and should NOT add their own callback on [CommandQueue].
+ */
+@SysUISingleton
+class StatusBarWindowStateController @Inject constructor(
+    @DisplayId private val thisDisplayId: Int,
+    commandQueue: CommandQueue
+) {
+    private val commandQueueCallback = object : CommandQueue.Callbacks {
+        override fun setWindowState(
+            displayId: Int,
+            @StatusBarManager.WindowType window: Int,
+            @WindowVisibleState state: Int
+        ) {
+            this@StatusBarWindowStateController.setWindowState(displayId, window, state)
+        }
+    }
+    private val listeners: MutableSet<StatusBarWindowStateListener> = HashSet()
+
+    @WindowVisibleState private var windowState: Int = WINDOW_STATE_SHOWING
+
+    init {
+        commandQueue.addCallback(commandQueueCallback)
+    }
+
+    /** Adds a listener. */
+    fun addListener(listener: StatusBarWindowStateListener) {
+        listeners.add(listener)
+    }
+
+    /** Returns true if the window is currently showing. */
+    fun windowIsShowing() = windowState == WINDOW_STATE_SHOWING
+
+    private fun setWindowState(
+        displayId: Int,
+        @StatusBarManager.WindowType window: Int,
+        @WindowVisibleState state: Int
+    ) {
+        if (displayId != thisDisplayId) {
+            return
+        }
+        if (window != WINDOW_STATUS_BAR) {
+            return
+        }
+        if (windowState == state) {
+            return
+        }
+
+        windowState = state
+        if (StatusBar.DEBUG_WINDOW_STATE) {
+            Log.d(StatusBar.TAG, "Status bar " + windowStateToString(state))
+        }
+        listeners.forEach { it.onStatusBarWindowStateChanged(state) }
+    }
+}
diff --git a/telephony/java/com/android/internal/telephony/euicc/IResultCallback.aidl b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowStateListener.kt
similarity index 67%
copy from telephony/java/com/android/internal/telephony/euicc/IResultCallback.aidl
copy to packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowStateListener.kt
index 69f479c..f3bab04 100644
--- a/telephony/java/com/android/internal/telephony/euicc/IResultCallback.aidl
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowStateListener.kt
@@ -13,11 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.internal.telephony.euicc;
 
-import android.content.Intent;
+package com.android.systemui.statusbar.window
 
-/** @hide */
-oneway interface IResultCallback {
-    void onComplete(int resultCode, in Intent resultIntent);
+import android.app.StatusBarManager
+
+/** Listener interface for changes in the status bar window state. */
+fun interface StatusBarWindowStateListener {
+    fun onStatusBarWindowStateChanged(@StatusBarManager.WindowVisibleState state: Int)
 }
diff --git a/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java b/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java
index 97fce51..05e5666 100644
--- a/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java
+++ b/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java
@@ -33,6 +33,7 @@
 import android.graphics.drawable.Drawable;
 import android.os.Build;
 import android.os.UserHandle;
+import android.util.IconDrawableFactory;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -40,10 +41,6 @@
 import android.widget.TextView;
 
 import com.android.internal.R;
-import com.android.launcher3.icons.BaseIconFactory.IconOptions;
-import com.android.launcher3.icons.IconFactory;
-import com.android.settingslib.applications.ApplicationsState;
-import com.android.settingslib.applications.ApplicationsState.AppEntry;
 import com.android.systemui.plugins.ToastPlugin;
 
 /**
@@ -199,7 +196,9 @@
                 iconView.setVisibility(View.GONE);
             } else {
                 iconView.setImageDrawable(icon);
-                if (appInfo.labelRes != 0) {
+                if (appInfo == null) {
+                    Log.d(TAG, "No appInfo for pkg=" + mPackageName + " usr=" + mUserId);
+                } else if (appInfo.labelRes != 0) {
                     try {
                         Resources res = mContext.getPackageManager().getResourcesForApplication(
                                 appInfo,
@@ -252,48 +251,29 @@
             return null;
         }
 
-        final Context userContext;
         try {
-            userContext = context.createPackageContextAsUser("android",
-                0, new UserHandle(userId));
+            final PackageManager packageManager = context.getPackageManager();
+            final ApplicationInfo appInfo = packageManager.getApplicationInfoAsUser(
+                    packageName,
+                    PackageManager.ApplicationInfoFlags.of(PackageManager.GET_META_DATA),
+                    userId);
+            if (appInfo == null || !showApplicationIcon(appInfo, packageManager)) {
+                return null;
+            }
+
+            IconDrawableFactory iconFactory = IconDrawableFactory.newInstance(context);
+            return iconFactory.getBadgedIcon(appInfo, UserHandle.getUserId(appInfo.uid));
         } catch (NameNotFoundException e) {
-            Log.e(TAG, "Could not create user package context");
+            Log.e(TAG, "Couldn't find application info for packageName=" + packageName
+                    + " userId=" + userId);
             return null;
         }
-
-        final ApplicationsState appState =
-                ApplicationsState.getInstance((Application) context.getApplicationContext());
-        if (!appState.isUserAdded(userId)) {
-            Log.d(TAG, "user hasn't been fully initialized, not showing an app icon for "
-                    + "packageName=" + packageName);
-            return null;
-        }
-
-        final PackageManager packageManager = userContext.getPackageManager();
-        final AppEntry appEntry = appState.getEntry(packageName, userId);
-        if (appEntry == null || appEntry.info == null
-                || !showApplicationIcon(appEntry.info, packageManager)) {
-            return null;
-        }
-
-        final ApplicationInfo appInfo = appEntry.info;
-        UserHandle user = UserHandle.getUserHandleForUid(appInfo.uid);
-        IconFactory iconFactory = IconFactory.obtain(context);
-        try {
-            return iconFactory.createBadgedIconBitmap(
-                        appInfo.loadUnbadgedIcon(packageManager),
-                        new IconOptions().setUser(user))
-                    .newIcon(context);
-        } finally {
-            iconFactory.recycle();
-        }
     }
 
     private static boolean showApplicationIcon(ApplicationInfo appInfo,
             PackageManager packageManager) {
         if (hasFlag(appInfo.flags, FLAG_UPDATED_SYSTEM_APP)) {
-            return packageManager.getLaunchIntentForPackage(appInfo.packageName)
-                != null;
+            return packageManager.getLaunchIntentForPackage(appInfo.packageName) != null;
         }
         return !hasFlag(appInfo.flags, FLAG_SYSTEM);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/unfold/FoldAodAnimationController.kt b/packages/SystemUI/src/com/android/systemui/unfold/FoldAodAnimationController.kt
index fb9df01..52c416ba 100644
--- a/packages/SystemUI/src/com/android/systemui/unfold/FoldAodAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/unfold/FoldAodAnimationController.kt
@@ -19,7 +19,6 @@
 import android.os.PowerManager
 import android.provider.Settings
 import com.android.systemui.keyguard.KeyguardViewMediator
-import com.android.systemui.keyguard.ScreenLifecycle
 import com.android.systemui.keyguard.WakefulnessLifecycle
 import com.android.systemui.statusbar.LightRevealScrim
 import com.android.systemui.statusbar.phone.ScreenOffAnimation
@@ -36,12 +35,10 @@
  */
 @SysUIUnfoldScope
 class FoldAodAnimationController @Inject constructor(
-    private val screenLifecycle: ScreenLifecycle,
     private val keyguardViewMediatorLazy: Lazy<KeyguardViewMediator>,
     private val wakefulnessLifecycle: WakefulnessLifecycle,
     private val globalSettings: GlobalSettings
-) : ScreenLifecycle.Observer,
-    CallbackController<FoldAodAnimationStatus>,
+) : CallbackController<FoldAodAnimationStatus>,
     ScreenOffAnimation,
     WakefulnessLifecycle.Observer {
 
@@ -58,7 +55,6 @@
     override fun initialize(statusBar: StatusBar, lightRevealScrim: LightRevealScrim) {
         this.statusBar = statusBar
 
-        screenLifecycle.addObserver(this)
         wakefulnessLifecycle.addObserver(this)
     }
 
@@ -123,7 +119,7 @@
         }
     }
 
-    override fun onScreenTurnedOn() {
+    fun onScreenTurnedOn() {
         if (shouldPlayAnimation) {
             statusBar.notificationPanelViewController.startFoldToAodAnimation {
                 // End action
diff --git a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt
index e6fc49f..0b89ef2 100644
--- a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt
+++ b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt
@@ -20,6 +20,7 @@
 import android.graphics.PixelFormat
 import android.hardware.devicestate.DeviceStateManager
 import android.hardware.devicestate.DeviceStateManager.FoldStateListener
+import android.hardware.input.InputManager
 import android.hardware.display.DisplayManager
 import android.os.Handler
 import android.os.Trace
@@ -195,8 +196,7 @@
         params.layoutInDisplayCutoutMode =
             WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
         params.fitInsetsTypes = 0
-        params.flags = (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
-            or WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE)
+        params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
         params.setTrustedOverlay()
 
         val packageName: String = context.opPackageName
@@ -239,6 +239,8 @@
             if (scrimView == null) {
                 addView()
             }
+            // Disable input dispatching during transition.
+            InputManager.getInstance().cancelCurrentTouch()
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionModule.kt b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionModule.kt
index cd3e2d3..75dfd48 100644
--- a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionModule.kt
@@ -58,7 +58,8 @@
                     deviceStateManager,
                     sensorManager,
                     handler,
-                    executor
+                    executor,
+                    tracingTagPrefix = "systemui"
                 )
             )
         } else {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/PendingDrawnTasksContainer.kt b/packages/SystemUI/src/com/android/systemui/util/concurrency/PendingTasksContainer.kt
similarity index 77%
rename from packages/SystemUI/src/com/android/systemui/keyguard/PendingDrawnTasksContainer.kt
rename to packages/SystemUI/src/com/android/systemui/util/concurrency/PendingTasksContainer.kt
index a60033c..6cd384f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/PendingDrawnTasksContainer.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/concurrency/PendingTasksContainer.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.keyguard
+package com.android.systemui.util.concurrency
 
 import android.os.Trace
 import java.util.concurrent.atomic.AtomicInteger
@@ -23,9 +23,9 @@
 /**
  * Allows to wait for multiple callbacks and notify when the last one is executed
  */
-class PendingDrawnTasksContainer {
+class PendingTasksContainer {
 
-    private var pendingDrawnTasksCount: AtomicInteger = AtomicInteger(0)
+    private var pendingTasksCount: AtomicInteger = AtomicInteger(0)
     private var completionCallback: AtomicReference<Runnable> = AtomicReference()
 
     /**
@@ -33,19 +33,19 @@
      * @return a runnable that should be invoked when the task is finished
      */
     fun registerTask(name: String): Runnable {
-        pendingDrawnTasksCount.incrementAndGet()
+        pendingTasksCount.incrementAndGet()
 
         if (ENABLE_TRACE) {
-            Trace.beginAsyncSection("PendingDrawnTasksContainer#$name", 0)
+            Trace.beginAsyncSection("PendingTasksContainer#$name", 0)
         }
 
         return Runnable {
-            if (pendingDrawnTasksCount.decrementAndGet() == 0) {
+            if (pendingTasksCount.decrementAndGet() == 0) {
                 val onComplete = completionCallback.getAndSet(null)
                 onComplete?.run()
 
                 if (ENABLE_TRACE) {
-                    Trace.endAsyncSection("PendingDrawnTasksContainer#$name", 0)
+                    Trace.endAsyncSection("PendingTasksContainer#$name", 0)
                 }
             }
         }
@@ -57,7 +57,7 @@
     fun reset() {
         // Create new objects in case if there are pending callbacks from the previous invocations
         completionCallback = AtomicReference()
-        pendingDrawnTasksCount = AtomicInteger(0)
+        pendingTasksCount = AtomicInteger(0)
     }
 
     /**
@@ -67,7 +67,7 @@
     fun onTasksComplete(onComplete: Runnable) {
         completionCallback.set(onComplete)
 
-        if (pendingDrawnTasksCount.get() == 0) {
+        if (pendingTasksCount.get() == 0) {
             val currentOnComplete = completionCallback.getAndSet(null)
             currentOnComplete?.run()
         }
@@ -76,7 +76,7 @@
     /**
      * Returns current pending tasks count
      */
-    fun getPendingCount(): Int = pendingDrawnTasksCount.get()
+    fun getPendingCount(): Int = pendingTasksCount.get()
 }
 
 private const val ENABLE_TRACE = false
diff --git a/packages/SystemUI/src/com/android/systemui/util/wrapper/RotationPolicyWrapper.kt b/packages/SystemUI/src/com/android/systemui/util/wrapper/RotationPolicyWrapper.kt
index 2a0cc7d..b64d7be 100644
--- a/packages/SystemUI/src/com/android/systemui/util/wrapper/RotationPolicyWrapper.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/wrapper/RotationPolicyWrapper.kt
@@ -17,8 +17,10 @@
 package com.android.systemui.util.wrapper
 
 import android.content.Context
+import android.provider.Settings.Secure.CAMERA_AUTOROTATE
 import com.android.internal.view.RotationPolicy
 import com.android.internal.view.RotationPolicy.RotationPolicyListener
+import com.android.systemui.util.settings.SecureSettings
 import javax.inject.Inject
 
 /**
@@ -30,12 +32,16 @@
     fun getRotationLockOrientation(): Int
     fun isRotationLockToggleVisible(): Boolean
     fun isRotationLocked(): Boolean
+    fun isCameraRotationEnabled(): Boolean
     fun registerRotationPolicyListener(listener: RotationPolicyListener, userHandle: Int)
     fun unregisterRotationPolicyListener(listener: RotationPolicyListener)
 }
 
-class RotationPolicyWrapperImpl @Inject constructor(private val context: Context) :
-    RotationPolicyWrapper {
+class RotationPolicyWrapperImpl @Inject constructor(
+    private val context: Context,
+    private val secureSettings: SecureSettings
+) :
+        RotationPolicyWrapper {
 
     override fun setRotationLock(enabled: Boolean) {
         RotationPolicy.setRotationLock(context, enabled)
@@ -54,6 +60,9 @@
     override fun isRotationLocked(): Boolean =
         RotationPolicy.isRotationLocked(context)
 
+    override fun isCameraRotationEnabled(): Boolean =
+            secureSettings.getInt(CAMERA_AUTOROTATE, 0) == 1
+
     override fun registerRotationPolicyListener(
         listener: RotationPolicyListener,
         userHandle: Int
diff --git a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletScreenController.java b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletScreenController.java
index 2e183b3..ba9b638 100644
--- a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletScreenController.java
+++ b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletScreenController.java
@@ -223,8 +223,7 @@
         }
         mUiEventLogger.log(WalletUiEvent.QAW_CLICK_CARD);
 
-        mActivityStarter.startActivity(
-                ((QAWalletCardViewInfo) cardInfo).mWalletCard.getPendingIntent().getIntent(), true);
+        mActivityStarter.startPendingIntentDismissingKeyguard(cardInfo.getPendingIntent());
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
index 4600bc7..31b17f8 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
@@ -258,11 +258,6 @@
             public void onKeyguardVisibilityChanged(boolean showing) {
                 splitScreen.onKeyguardVisibilityChanged(showing);
             }
-
-            @Override
-            public void onKeyguardOccludedChanged(boolean occluded) {
-                splitScreen.onKeyguardOccludedChanged(occluded);
-            }
         };
         mKeyguardUpdateMonitor.registerCallback(mSplitScreenKeyguardCallback);
 
@@ -271,11 +266,6 @@
             public void onFinishedWakingUp() {
                 splitScreen.onFinishedWakingUp();
             }
-
-            @Override
-            public void onFinishedGoingToSleep() {
-                splitScreen.onFinishedGoingToSleep();
-            }
         });
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/mediator/ScreenOnCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/mediator/ScreenOnCoordinatorTest.kt
new file mode 100644
index 0000000..96e6bd1
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/mediator/ScreenOnCoordinatorTest.kt
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.mediator
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.keyguard.ScreenLifecycle
+import com.android.systemui.unfold.FoldAodAnimationController
+import com.android.systemui.unfold.SysUIUnfoldComponent
+import com.android.systemui.unfold.UnfoldLightRevealOverlayAnimation
+import com.android.systemui.util.concurrency.FakeExecution
+import com.android.systemui.util.mockito.capture
+
+import java.util.Optional
+
+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.Mockito.`when`
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class ScreenOnCoordinatorTest : SysuiTestCase() {
+
+    @Mock
+    private lateinit var runnable: Runnable
+    @Mock
+    private lateinit var unfoldComponent: SysUIUnfoldComponent
+    @Mock
+    private lateinit var foldAodAnimationController: FoldAodAnimationController
+    @Mock
+    private lateinit var unfoldAnimation: UnfoldLightRevealOverlayAnimation
+    @Mock
+    private lateinit var screenLifecycle: ScreenLifecycle
+    @Captor
+    private lateinit var readyCaptor: ArgumentCaptor<Runnable>
+
+    private lateinit var screenOnCoordinator: ScreenOnCoordinator
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+
+        `when`(unfoldComponent.getUnfoldLightRevealOverlayAnimation())
+                .thenReturn(unfoldAnimation)
+        `when`(unfoldComponent.getFoldAodAnimationController())
+                .thenReturn(foldAodAnimationController)
+
+        screenOnCoordinator = ScreenOnCoordinator(
+            screenLifecycle,
+            Optional.of(unfoldComponent),
+            FakeExecution()
+        )
+
+        // Make sure screen events are registered to observe
+        verify(screenLifecycle).addObserver(screenOnCoordinator)
+    }
+
+    @Test
+    fun testUnfoldTransitionEnabledDrawnTasksReady_onScreenTurningOn_callsDrawnCallback() {
+        screenOnCoordinator.onScreenTurningOn(runnable)
+
+        onUnfoldOverlayReady()
+        onFoldAodReady()
+
+        // Should be called when both unfold overlay and keyguard drawn ready
+        verify(runnable).run()
+    }
+
+    @Test
+    fun testUnfoldTransitionDisabledDrawnTasksReady_onScreenTurningOn_callsDrawnCallback() {
+        // Recreate with empty unfoldComponent
+        screenOnCoordinator = ScreenOnCoordinator(
+            screenLifecycle,
+            Optional.empty(),
+            FakeExecution()
+        )
+        screenOnCoordinator.onScreenTurningOn(runnable)
+
+        // Should be called when only keyguard drawn
+        verify(runnable).run()
+    }
+
+    @Test
+    fun testWakeAndUnlockDelaysRunnable() {
+        // GIVEN wakeAndUnlocking has been set to true
+        screenOnCoordinator.wakeAndUnlocking = true
+
+        // WHEN the screen turns on and two tasks have completed
+        screenOnCoordinator.onScreenTurningOn(runnable)
+        onUnfoldOverlayReady()
+        onFoldAodReady()
+
+        // THEN the runnable should not have run yet
+        verify(runnable, never()).run()
+
+        // WHEN the value of wakeAndUnlocking changes
+        screenOnCoordinator.wakeAndUnlocking = false
+
+        // THEN the runnable should have run, as it is the last task to complete
+        verify(runnable).run()
+    }
+
+    private fun onUnfoldOverlayReady() {
+        verify(unfoldAnimation).onScreenTurningOn(capture(readyCaptor))
+        readyCaptor.getValue().run()
+    }
+
+    private fun onFoldAodReady() {
+        verify(foldAodAnimationController).onScreenTurningOn(capture(readyCaptor))
+        readyCaptor.getValue().run()
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
index 4f3266d..40632a8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
@@ -44,8 +44,10 @@
 import com.android.systemui.statusbar.SmartReplyController;
 
 import org.junit.After;
+import org.junit.AfterClass;
 import org.junit.Before;
 import org.junit.Rule;
+import org.mockito.Mockito;
 
 import java.io.FileInputStream;
 import java.io.IOException;
@@ -120,11 +122,15 @@
             TestableLooper.get(this).processAllMessages();
         }
         disallowTestableLooperAsMainThread();
-        SystemUIFactory.cleanup();
         mContext.cleanUpReceivers(this.getClass().getSimpleName());
         mFakeBroadcastDispatcher.cleanUpReceivers(this.getClass().getSimpleName());
     }
 
+    @AfterClass
+    public static void mockitoTearDown() {
+        Mockito.framework().clearInlineMocks();
+    }
+
     /**
      * Tests are run on the TestableLooper; however, there are parts of SystemUI that assert that
      * the code is run from the main looper. Therefore, we allow the TestableLooper to pass these
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 8dd5d6c..08c7714 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
@@ -29,6 +29,7 @@
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -53,12 +54,14 @@
 import android.hardware.fingerprint.FingerprintManager;
 import android.hardware.fingerprint.FingerprintSensorProperties;
 import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
+import android.hardware.fingerprint.FingerprintStateListener;
 import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.RemoteException;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableContext;
+import android.testing.TestableLooper;
 import android.testing.TestableLooper.RunWithLooper;
 import android.view.WindowManager;
 
@@ -67,6 +70,8 @@
 import com.android.internal.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.util.concurrency.Execution;
+import com.android.systemui.util.concurrency.FakeExecution;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -112,20 +117,27 @@
     private SidefpsController mSidefpsController;
     @Mock
     private DisplayManager mDisplayManager;
-    @Mock
-    private Handler mHandler;
     @Captor
     ArgumentCaptor<IFingerprintAuthenticatorsRegisteredCallback> mAuthenticatorsRegisteredCaptor;
+    @Captor
+    ArgumentCaptor<FingerprintStateListener> mFingerprintStateCaptor;
 
+    private TestableContext mContextSpy;
+    private Execution mExecution;
+    private TestableLooper mTestableLooper;
+    private Handler mHandler;
     private TestableAuthController mAuthController;
 
     @Before
     public void setup() throws RemoteException {
         MockitoAnnotations.initMocks(this);
 
-        TestableContext context = spy(mContext);
+        mContextSpy = spy(mContext);
+        mExecution = new FakeExecution();
+        mTestableLooper = TestableLooper.get(this);
+        mHandler = new Handler(mTestableLooper.getLooper());
 
-        when(context.getPackageManager()).thenReturn(mPackageManager);
+        when(mContextSpy.getPackageManager()).thenReturn(mPackageManager);
         when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE))
                 .thenReturn(true);
         when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT))
@@ -158,21 +170,78 @@
         props.add(prop);
         when(mFingerprintManager.getSensorPropertiesInternal()).thenReturn(props);
 
-        mAuthController = new TestableAuthController(context, mCommandQueue,
+        mAuthController = new TestableAuthController(mContextSpy, mExecution, mCommandQueue,
                 mActivityTaskManager, mWindowManager, mFingerprintManager, mFaceManager,
                 () -> mUdfpsController, () -> mSidefpsController);
 
         mAuthController.start();
         verify(mFingerprintManager).addAuthenticatorsRegisteredCallback(
                 mAuthenticatorsRegisteredCaptor.capture());
+
         mAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(props);
+
+        // Ensures that the operations posted on the handler get executed.
+        mTestableLooper.processAllMessages();
     }
 
     // Callback tests
 
     @Test
+    public void testRegistersFingerprintStateListener_afterAllAuthenticatorsAreRegistered()
+            throws RemoteException {
+        // This test is sensitive to prior FingerprintManager interactions.
+        reset(mFingerprintManager);
+
+        // This test requires an uninitialized AuthController.
+        AuthController authController = new TestableAuthController(mContextSpy, mExecution,
+                mCommandQueue, mActivityTaskManager, mWindowManager, mFingerprintManager,
+                mFaceManager, () -> mUdfpsController, () -> mSidefpsController);
+        authController.start();
+
+        verify(mFingerprintManager).addAuthenticatorsRegisteredCallback(
+                mAuthenticatorsRegisteredCaptor.capture());
+        mTestableLooper.processAllMessages();
+
+        verify(mFingerprintManager, never()).registerFingerprintStateListener(any());
+
+        mAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(new ArrayList<>());
+        mTestableLooper.processAllMessages();
+
+        verify(mFingerprintManager).registerFingerprintStateListener(any());
+    }
+
+    @Test
+    public void testDoesNotCrash_afterEnrollmentsChangedForUnknownSensor() throws RemoteException {
+        // This test is sensitive to prior FingerprintManager interactions.
+        reset(mFingerprintManager);
+
+        // This test requires an uninitialized AuthController.
+        AuthController authController = new TestableAuthController(mContextSpy, mExecution,
+                mCommandQueue, mActivityTaskManager, mWindowManager, mFingerprintManager,
+                mFaceManager, () -> mUdfpsController, () -> mSidefpsController);
+        authController.start();
+
+        verify(mFingerprintManager).addAuthenticatorsRegisteredCallback(
+                mAuthenticatorsRegisteredCaptor.capture());
+
+        // Emulates a device with no authenticators (empty list).
+        mAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(new ArrayList<>());
+        mTestableLooper.processAllMessages();
+
+        verify(mFingerprintManager).registerFingerprintStateListener(
+                mFingerprintStateCaptor.capture());
+
+        // Enrollments changed for an unknown sensor.
+        mFingerprintStateCaptor.getValue().onEnrollmentsChanged(0 /* userId */,
+                0xbeef /* sensorId */, true /* hasEnrollments */);
+        mTestableLooper.processAllMessages();
+
+        // Nothing should crash.
+    }
+
+    @Test
     public void testSendsReasonUserCanceled_whenDismissedByUserCancel() throws Exception {
-        showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
+        showDialog(new int[]{1} /* sensorIds */, false /* credentialAllowed */);
         mAuthController.onDismissed(AuthDialogCallback.DISMISSED_USER_CANCELED,
                 null /* credentialAttestation */);
         verify(mReceiver).onDialogDismissed(
@@ -497,7 +566,7 @@
         when(mActivityTaskManager.getTasks(anyInt())).thenReturn(tasks);
 
         mAuthController.mTaskStackListener.onTaskStackChanged();
-        waitForIdleSync();
+        mTestableLooper.processAllMessages();
 
         assertNull(mAuthController.mCurrentDialog);
         assertNull(mAuthController.mReceiver);
@@ -528,7 +597,7 @@
         showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
         Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
         mAuthController.mBroadcastReceiver.onReceive(mContext, intent);
-        waitForIdleSync();
+        mTestableLooper.processAllMessages();
 
         assertNull(mAuthController.mCurrentDialog);
         assertNull(mAuthController.mReceiver);
@@ -598,6 +667,7 @@
         private PromptInfo mLastBiometricPromptInfo;
 
         TestableAuthController(Context context,
+                Execution execution,
                 CommandQueue commandQueue,
                 ActivityTaskManager activityTaskManager,
                 WindowManager windowManager,
@@ -605,7 +675,7 @@
                 FaceManager faceManager,
                 Provider<UdfpsController> udfpsControllerFactory,
                 Provider<SidefpsController> sidefpsControllerFactory) {
-            super(context, commandQueue, activityTaskManager, windowManager,
+            super(context, execution, commandQueue, activityTaskManager, windowManager,
                     fingerprintManager, faceManager, udfpsControllerFactory,
                     sidefpsControllerFactory, mDisplayManager, mHandler);
         }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
index 2c4808a..5128ccc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
@@ -131,7 +131,7 @@
             false /* isStrongBiometric */)
 
         // THEN update sensor location and show ripple
-        verify(rippleView).setSensorLocation(fpsLocation)
+        verify(rippleView).setFingerprintSensorLocation(fpsLocation, -1f)
         verify(rippleView).startUnlockedRipple(any())
     }
 
@@ -292,10 +292,10 @@
 
         reset(rippleView)
         captor.value.onThemeChanged()
-        verify(rippleView).setColor(ArgumentMatchers.anyInt())
+        verify(rippleView).setLockScreenColor(ArgumentMatchers.anyInt())
 
         reset(rippleView)
         captor.value.onUiModeChanged()
-        verify(rippleView).setColor(ArgumentMatchers.anyInt())
+        verify(rippleView).setLockScreenColor(ArgumentMatchers.anyInt())
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricTestExtensions.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricTestExtensions.kt
new file mode 100644
index 0000000..57f3617
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricTestExtensions.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.biometrics
+
+import android.hardware.biometrics.ComponentInfoInternal
+import android.hardware.biometrics.SensorLocationInternal
+import android.hardware.biometrics.SensorProperties
+import android.hardware.fingerprint.FingerprintSensorProperties
+import android.hardware.fingerprint.FingerprintSensorPropertiesInternal
+
+/** Creates properties from the sensor location with test values. */
+fun SensorLocationInternal.asFingerprintSensorProperties(
+    sensorId: Int = 22,
+    @SensorProperties.Strength sensorStrength: Int = SensorProperties.STRENGTH_WEAK,
+    @FingerprintSensorProperties.SensorType sensorType: Int =
+        FingerprintSensorProperties.TYPE_UDFPS_OPTICAL,
+    maxEnrollmentsPerUser: Int = 1,
+    info: List<ComponentInfoInternal> = listOf(ComponentInfoInternal("a", "b", "c", "d", "e")),
+    resetLockoutRequiresHardwareAuthToken: Boolean = false
+) = FingerprintSensorPropertiesInternal(
+    sensorId,
+    sensorStrength,
+    maxEnrollmentsPerUser,
+    info,
+    sensorType,
+    resetLockoutRequiresHardwareAuthToken,
+    listOf(this)
+)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
new file mode 100644
index 0000000..84eb935
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.biometrics
+
+import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_BP
+import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_KEYGUARD
+import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_OTHER
+import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_SETTINGS
+import android.hardware.biometrics.BiometricOverlayConstants.REASON_ENROLL_ENROLLING
+import android.hardware.biometrics.BiometricOverlayConstants.REASON_ENROLL_FIND_SENSOR
+import android.hardware.biometrics.BiometricOverlayConstants.ShowReason
+import android.hardware.biometrics.SensorLocationInternal
+import android.hardware.fingerprint.FingerprintManager
+import android.hardware.fingerprint.IUdfpsOverlayControllerCallback
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper.RunWithLooper
+import android.view.LayoutInflater
+import android.view.MotionEvent
+import android.view.View
+import android.view.WindowManager
+import android.view.accessibility.AccessibilityManager
+import androidx.test.filters.SmallTest
+import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.statusbar.LockscreenShadeTransitionController
+import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
+import com.android.systemui.statusbar.phone.SystemUIDialogManager
+import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController
+import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager
+import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.statusbar.policy.KeyguardStateController
+import com.android.systemui.util.time.SystemClock
+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.ArgumentMatchers.any
+import org.mockito.ArgumentMatchers.eq
+import org.mockito.Mock
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.`when` as whenever
+import org.mockito.Mockito.verify
+import org.mockito.junit.MockitoJUnit
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@RunWithLooper(setAsMainLooper = true)
+class UdfpsControllerOverlayTest : SysuiTestCase() {
+
+    @JvmField @Rule
+    var rule = MockitoJUnit.rule()
+
+    @Mock private lateinit var fingerprintManager: FingerprintManager
+    @Mock private lateinit var inflater: LayoutInflater
+    @Mock private lateinit var windowManager: WindowManager
+    @Mock private lateinit var accessibilityManager: AccessibilityManager
+    @Mock private lateinit var statusBarStateController: StatusBarStateController
+    @Mock private lateinit var panelExpansionStateManager: PanelExpansionStateManager
+    @Mock private lateinit var statusBarKeyguardViewManager: StatusBarKeyguardViewManager
+    @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
+    @Mock private lateinit var dialogManager: SystemUIDialogManager
+    @Mock private lateinit var dumpManager: DumpManager
+    @Mock private lateinit var transitionController: LockscreenShadeTransitionController
+    @Mock private lateinit var configurationController: ConfigurationController
+    @Mock private lateinit var systemClock: SystemClock
+    @Mock private lateinit var keyguardStateController: KeyguardStateController
+    @Mock
+    private lateinit var unlockedScreenOffAnimationController: UnlockedScreenOffAnimationController
+    @Mock private lateinit var hbmProvider: UdfpsHbmProvider
+    @Mock private lateinit var controllerCallback: IUdfpsOverlayControllerCallback
+    @Mock private lateinit var udfpsController: UdfpsController
+    @Mock private lateinit var udfpsView: UdfpsView
+    @Mock private lateinit var udfpsEnrollView: UdfpsEnrollView
+
+    private val sensorProps = SensorLocationInternal("", 10, 100, 20)
+        .asFingerprintSensorProperties()
+    private val onTouch = { _: View, _: MotionEvent, _: Boolean -> true }
+    private lateinit var controllerOverlay: UdfpsControllerOverlay
+
+    @Before
+    fun setup() {
+        context.orCreateTestableResources.addOverride(R.integer.config_udfpsEnrollProgressBar, 20)
+        whenever(inflater.inflate(R.layout.udfps_view, null, false))
+            .thenReturn(udfpsView)
+        whenever(inflater.inflate(R.layout.udfps_enroll_view, null))
+            .thenReturn(udfpsEnrollView)
+        whenever(inflater.inflate(R.layout.udfps_bp_view, null))
+            .thenReturn(mock(UdfpsBpView::class.java))
+        whenever(inflater.inflate(R.layout.udfps_keyguard_view, null))
+            .thenReturn(mock(UdfpsKeyguardView::class.java))
+        whenever(inflater.inflate(R.layout.udfps_fpm_other_view, null))
+            .thenReturn(mock(UdfpsFpmOtherView::class.java))
+        whenever(udfpsEnrollView.context).thenReturn(context)
+    }
+
+    private fun withReason(@ShowReason reason: Int, block: () -> Unit) {
+        controllerOverlay = UdfpsControllerOverlay(
+            context, fingerprintManager, inflater, windowManager, accessibilityManager,
+            statusBarStateController, panelExpansionStateManager, statusBarKeyguardViewManager,
+            keyguardUpdateMonitor, dialogManager, dumpManager, transitionController,
+            configurationController, systemClock, keyguardStateController,
+            unlockedScreenOffAnimationController, sensorProps, hbmProvider, reason,
+            controllerCallback, onTouch)
+        block()
+    }
+
+    @Test
+    fun showUdfpsOverlay_bp() = withReason(REASON_AUTH_BP) { showUdfpsOverlay() }
+
+    @Test
+    fun showUdfpsOverlay_keyguard() = withReason(REASON_AUTH_KEYGUARD) { showUdfpsOverlay() }
+
+    @Test
+    fun showUdfpsOverlay_settings() = withReason(REASON_AUTH_SETTINGS) { showUdfpsOverlay() }
+
+    @Test
+    fun showUdfpsOverlay_locate() = withReason(REASON_ENROLL_FIND_SENSOR) {
+        showUdfpsOverlay(isEnrollUseCase = true)
+    }
+
+    @Test
+    fun showUdfpsOverlay_enroll() = withReason(REASON_ENROLL_ENROLLING) {
+        showUdfpsOverlay(isEnrollUseCase = true)
+    }
+
+    @Test
+    fun showUdfpsOverlay_other() = withReason(REASON_AUTH_OTHER) { showUdfpsOverlay() }
+
+    private fun showUdfpsOverlay(isEnrollUseCase: Boolean = false) {
+        val didShow = controllerOverlay.show(udfpsController)
+
+        verify(windowManager).addView(eq(controllerOverlay.overlayView), any())
+        verify(udfpsView).setHbmProvider(eq(hbmProvider))
+        verify(udfpsView).sensorProperties = eq(sensorProps)
+        verify(udfpsView).animationViewController = any()
+        verify(udfpsView).addView(any())
+
+        assertThat(didShow).isTrue()
+        assertThat(controllerOverlay.isShowing).isTrue()
+        assertThat(controllerOverlay.isHiding).isFalse()
+        assertThat(controllerOverlay.overlayView).isNotNull()
+        if (isEnrollUseCase) {
+            verify(udfpsEnrollView).updateSensorLocation(eq(sensorProps))
+            assertThat(controllerOverlay.enrollHelper).isNotNull()
+        } else {
+            assertThat(controllerOverlay.enrollHelper).isNull()
+        }
+    }
+
+    @Test
+    fun hideUdfpsOverlay_bp() = withReason(REASON_AUTH_BP) { hideUdfpsOverlay() }
+
+    @Test
+    fun hideUdfpsOverlay_keyguard() = withReason(REASON_AUTH_KEYGUARD) { hideUdfpsOverlay() }
+
+    @Test
+    fun hideUdfpsOverlay_settings() = withReason(REASON_AUTH_SETTINGS) { hideUdfpsOverlay() }
+
+    @Test
+    fun hideUdfpsOverlay_locate() = withReason(REASON_ENROLL_FIND_SENSOR) { hideUdfpsOverlay() }
+
+    @Test
+    fun hideUdfpsOverlay_enroll() = withReason(REASON_ENROLL_ENROLLING) { hideUdfpsOverlay() }
+
+    @Test
+    fun hideUdfpsOverlay_other() = withReason(REASON_AUTH_OTHER) { hideUdfpsOverlay() }
+
+    private fun hideUdfpsOverlay() {
+        val didShow = controllerOverlay.show(udfpsController)
+        val view = controllerOverlay.overlayView
+        val didHide = controllerOverlay.hide()
+
+        verify(windowManager).removeView(eq(view))
+
+        assertThat(didShow).isTrue()
+        assertThat(didHide).isTrue()
+        assertThat(controllerOverlay.overlayView).isNull()
+        assertThat(controllerOverlay.animationViewController).isNull()
+        assertThat(controllerOverlay.isShowing).isFalse()
+        assertThat(controllerOverlay.isHiding).isTrue()
+    }
+
+    @Test
+    fun canNotHide() = withReason(REASON_AUTH_BP) {
+        assertThat(controllerOverlay.hide()).isFalse()
+    }
+
+    @Test
+    fun canNotReshow() = withReason(REASON_AUTH_BP) {
+        assertThat(controllerOverlay.show(udfpsController)).isTrue()
+        assertThat(controllerOverlay.show(udfpsController)).isFalse()
+    }
+
+    @Test
+    fun forwardEnrollProgressEvents() = withReason(REASON_ENROLL_ENROLLING) {
+        controllerOverlay.show(udfpsController)
+
+        with(EnrollListener(controllerOverlay)) {
+            controllerOverlay.onEnrollmentProgress(/* remaining */20)
+            controllerOverlay.onAcquiredGood()
+            assertThat(progress).isTrue()
+            assertThat(help).isFalse()
+            assertThat(acquired).isFalse()
+        }
+    }
+
+    @Test
+    fun forwardEnrollHelpEvents() = withReason(REASON_ENROLL_ENROLLING) {
+        controllerOverlay.show(udfpsController)
+
+        with(EnrollListener(controllerOverlay)) {
+            controllerOverlay.onEnrollmentHelp()
+            assertThat(progress).isFalse()
+            assertThat(help).isTrue()
+            assertThat(acquired).isFalse()
+        }
+    }
+
+    @Test
+    fun forwardEnrollAcquiredEvents() = withReason(REASON_ENROLL_ENROLLING) {
+        controllerOverlay.show(udfpsController)
+
+        with(EnrollListener(controllerOverlay)) {
+            controllerOverlay.onEnrollmentProgress(/* remaining */ 1)
+            controllerOverlay.onAcquiredGood()
+            assertThat(progress).isTrue()
+            assertThat(help).isFalse()
+            assertThat(acquired).isTrue()
+        }
+    }
+
+    @Test
+    fun cancels() = withReason(REASON_AUTH_BP) {
+        controllerOverlay.cancel()
+        verify(controllerCallback).onUserCanceled()
+    }
+
+    @Test
+    fun stopIlluminatingOnHide() = withReason(REASON_AUTH_BP) {
+        whenever(udfpsView.isIlluminationRequested).thenReturn(true)
+
+        controllerOverlay.show(udfpsController)
+        controllerOverlay.hide()
+        verify(udfpsView).stopIllumination()
+    }
+}
+
+private class EnrollListener(
+    overlay: UdfpsControllerOverlay,
+    var progress: Boolean = false,
+    var help: Boolean = false,
+    var acquired: Boolean = false
+) : UdfpsEnrollHelper.Listener {
+
+    init {
+        overlay.enrollHelper!!.setListener(this)
+    }
+
+    override fun onEnrollmentProgress(remaining: Int, totalSteps: Int) {
+        progress = true
+    }
+
+    override fun onEnrollmentHelp(remaining: Int, totalSteps: Int) {
+        help = true
+    }
+
+    override fun onLastStepAcquired() {
+        acquired = true
+    }
+}
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 1dea678..2afcbda 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -24,6 +24,7 @@
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.inOrder;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
@@ -53,6 +54,7 @@
 
 import androidx.test.filters.SmallTest;
 
+import com.android.internal.util.LatencyTracker;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
@@ -81,6 +83,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.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
@@ -154,7 +157,8 @@
     private SystemClock mSystemClock;
     @Mock
     private UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
-
+    @Mock
+    private LatencyTracker mLatencyTracker;
     private FakeExecutor mFgExecutor;
 
     // Stuff for configuring mocks
@@ -163,9 +167,13 @@
     @Mock
     private UdfpsEnrollView mEnrollView;
     @Mock
-    private UdfpsKeyguardView mKeyguardView;
+    private UdfpsBpView mBpView;
     @Mock
-    private UdfpsKeyguardViewController mUdfpsKeyguardViewController;
+    private UdfpsFpmOtherView mFpmOtherView;
+    @Mock
+    private UdfpsKeyguardView mKeyguardView;
+    private UdfpsAnimationViewController mUdfpsKeyguardViewController =
+            mock(UdfpsKeyguardViewController.class);
     @Mock
     private TypedArray mBrightnessValues;
     @Mock
@@ -192,6 +200,10 @@
                 .thenReturn(mEnrollView); // for showOverlay REASON_ENROLL_ENROLLING
         when(mLayoutInflater.inflate(R.layout.udfps_keyguard_view, null))
                 .thenReturn(mKeyguardView); // for showOverlay REASON_AUTH_FPM_KEYGUARD
+        when(mLayoutInflater.inflate(R.layout.udfps_bp_view, null))
+                .thenReturn(mBpView);
+        when(mLayoutInflater.inflate(R.layout.udfps_fpm_other_view, null))
+                .thenReturn(mFpmOtherView);
         when(mEnrollView.getContext()).thenReturn(mContext);
         when(mKeyguardStateController.isOccluded()).thenReturn(false);
         final List<FingerprintSensorPropertiesInternal> props = new ArrayList<>();
@@ -239,7 +251,8 @@
                 mConfigurationController,
                 mSystemClock,
                 mUnlockedScreenOffAnimationController,
-                mSystemUIDialogManager);
+                mSystemUIDialogManager,
+                mLatencyTracker);
         verify(mFingerprintManager).setUdfpsOverlayController(mOverlayCaptor.capture());
         mOverlayController = mOverlayCaptor.getValue();
         verify(mScreenLifecycle).addObserver(mScreenObserverCaptor.capture());
@@ -340,7 +353,7 @@
         when(mKeyguardStateController.canDismissLockScreen()).thenReturn(false);
         when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
         when(mUdfpsView.getAnimationViewController()).thenReturn(
-                mock(UdfpsEnrollViewController.class));
+                (UdfpsAnimationViewController) mock(UdfpsEnrollViewController.class));
 
         // GIVEN that the overlay is showing
         mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
@@ -406,83 +419,6 @@
     }
 
     @Test
-    public void showUdfpsOverlay_addsViewToWindow_bp() throws RemoteException {
-        showUdfpsOverlay_addsViewToWindow(BiometricOverlayConstants.REASON_AUTH_BP);
-    }
-
-    @Test
-    public void showUdfpsOverlay_addsViewToWindow_keyguard() throws RemoteException {
-        showUdfpsOverlay_addsViewToWindow(BiometricOverlayConstants.REASON_AUTH_KEYGUARD);
-    }
-
-    @Test
-    public void showUdfpsOverlay_addsViewToWindow_settings() throws RemoteException {
-        showUdfpsOverlay_addsViewToWindow(BiometricOverlayConstants.REASON_AUTH_SETTINGS);
-    }
-
-    @Test
-    public void showUdfpsOverlay_addsViewToWindow_enroll_locate() throws RemoteException {
-        showUdfpsOverlay_addsViewToWindow(BiometricOverlayConstants.REASON_ENROLL_FIND_SENSOR);
-    }
-
-    @Test
-    public void showUdfpsOverlay_addsViewToWindow_enroll() throws RemoteException {
-        showUdfpsOverlay_addsViewToWindow(BiometricOverlayConstants.REASON_ENROLL_ENROLLING);
-    }
-
-    @Test
-    public void showUdfpsOverlay_addsViewToWindow_other() throws RemoteException {
-        showUdfpsOverlay_addsViewToWindow(BiometricOverlayConstants.REASON_AUTH_OTHER);
-    }
-
-    private void showUdfpsOverlay_addsViewToWindow(
-            @BiometricOverlayConstants.ShowReason int reason) throws RemoteException {
-        mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID, reason,
-                mUdfpsOverlayControllerCallback);
-        mFgExecutor.runAllReady();
-        verify(mWindowManager).addView(eq(mUdfpsView), any());
-    }
-
-    @Test
-    public void hideUdfpsOverlay_removesViewFromWindow_bp() throws RemoteException {
-        hideUdfpsOverlay_removesViewFromWindow(BiometricOverlayConstants.REASON_AUTH_BP);
-    }
-
-    @Test
-    public void hideUdfpsOverlay_removesViewFromWindow_keyguard() throws RemoteException {
-        hideUdfpsOverlay_removesViewFromWindow(BiometricOverlayConstants.REASON_AUTH_KEYGUARD);
-    }
-
-    @Test
-    public void hideUdfpsOverlay_removesViewFromWindow_settings() throws RemoteException {
-        hideUdfpsOverlay_removesViewFromWindow(BiometricOverlayConstants.REASON_AUTH_SETTINGS);
-    }
-
-    @Test
-    public void hideUdfpsOverlay_removesViewFromWindow_enroll_locate() throws RemoteException {
-        hideUdfpsOverlay_removesViewFromWindow(BiometricOverlayConstants.REASON_ENROLL_FIND_SENSOR);
-    }
-
-    @Test
-    public void hideUdfpsOverlay_removesViewFromWindow_enroll() throws RemoteException {
-        hideUdfpsOverlay_removesViewFromWindow(BiometricOverlayConstants.REASON_ENROLL_ENROLLING);
-    }
-
-    @Test
-    public void hideUdfpsOverlay_removesViewFromWindow_other() throws RemoteException {
-        hideUdfpsOverlay_removesViewFromWindow(BiometricOverlayConstants.REASON_AUTH_OTHER);
-    }
-
-    private void hideUdfpsOverlay_removesViewFromWindow(
-            @BiometricOverlayConstants.ShowReason int reason) throws RemoteException {
-        mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
-                BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
-        mOverlayController.hideUdfpsOverlay(TEST_UDFPS_SENSOR_ID);
-        mFgExecutor.runAllReady();
-        verify(mWindowManager).removeView(eq(mUdfpsView));
-    }
-
-    @Test
     public void hideUdfpsOverlay_resetsAltAuthBouncerWhenShowing() throws RemoteException {
         // GIVEN overlay was showing and the udfps bouncer is showing
         mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
@@ -532,11 +468,15 @@
         // THEN FingerprintManager is notified about onPointerDown
         verify(mFingerprintManager).onPointerDown(eq(mUdfpsController.mSensorProps.sensorId), eq(0),
                 eq(0), eq(0f), eq(0f));
+        verify(mLatencyTracker).onActionStart(eq(LatencyTracker.ACTION_UDFPS_ILLUMINATE));
         // AND illumination begins
         verify(mUdfpsView).startIllumination(mOnIlluminatedRunnableCaptor.capture());
+        verify(mLatencyTracker, never()).onActionEnd(eq(LatencyTracker.ACTION_UDFPS_ILLUMINATE));
         // AND onIlluminatedRunnable notifies FingerprintManager about onUiReady
         mOnIlluminatedRunnableCaptor.getValue().run();
-        verify(mFingerprintManager).onUiReady(eq(mUdfpsController.mSensorProps.sensorId));
+        InOrder inOrder = inOrder(mFingerprintManager, mLatencyTracker);
+        inOrder.verify(mFingerprintManager).onUiReady(eq(mUdfpsController.mSensorProps.sensorId));
+        inOrder.verify(mLatencyTracker).onActionEnd(eq(LatencyTracker.ACTION_UDFPS_ILLUMINATE));
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsViewTest.kt
new file mode 100644
index 0000000..2cd470e
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsViewTest.kt
@@ -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.systemui.biometrics
+
+import android.graphics.PointF
+import android.graphics.RectF
+import android.hardware.biometrics.SensorLocationInternal
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.testing.ViewUtils
+import android.view.LayoutInflater
+import android.view.Surface
+import androidx.test.filters.SmallTest
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.withArgCaptor
+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 org.mockito.Mock
+import org.mockito.Mockito.anyInt
+import org.mockito.Mockito.nullable
+import org.mockito.Mockito.never
+import org.mockito.Mockito.`when` as whenever
+import org.mockito.Mockito.verify
+import org.mockito.junit.MockitoJUnit
+
+private const val DISPLAY_ID = "" // default display id
+private const val SENSOR_X = 50
+private const val SENSOR_Y = 250
+private const val SENSOR_RADIUS = 10
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
+class UdfpsViewTest : SysuiTestCase() {
+
+    @JvmField @Rule
+    var rule = MockitoJUnit.rule()
+
+    @Mock
+    lateinit var hbmProvider: UdfpsHbmProvider
+    @Mock
+    lateinit var animationViewController: UdfpsAnimationViewController<UdfpsAnimationView>
+
+    private lateinit var view: UdfpsView
+
+    @Before
+    fun setup() {
+        context.setTheme(R.style.Theme_AppCompat)
+        context.orCreateTestableResources.addOverride(
+            com.android.internal.R.integer.config_udfps_illumination_transition_ms, 0)
+        view = LayoutInflater.from(context).inflate(R.layout.udfps_view, null) as UdfpsView
+        view.animationViewController = animationViewController
+        view.sensorProperties =
+            SensorLocationInternal(DISPLAY_ID, SENSOR_X, SENSOR_Y, SENSOR_RADIUS)
+                .asFingerprintSensorProperties()
+        view.setHbmProvider(hbmProvider)
+        ViewUtils.attachView(view)
+    }
+
+    @After
+    fun cleanup() {
+        ViewUtils.detachView(view)
+    }
+
+    @Test
+    fun forwardsEvents() {
+        view.dozeTimeTick()
+        verify(animationViewController).dozeTimeTick()
+
+        view.onTouchOutsideView()
+        verify(animationViewController).onTouchOutsideView()
+    }
+
+    @Test
+    fun layoutSizeFitsSensor() {
+        val params = withArgCaptor<RectF> {
+            verify(animationViewController).onSensorRectUpdated(capture())
+        }
+        assertThat(params.width()).isAtLeast(2f * SENSOR_RADIUS)
+        assertThat(params.height()).isAtLeast(2f * SENSOR_RADIUS)
+    }
+
+    @Test
+    fun isWithinSensorAreaAndPaused() = isWithinSensorArea(paused = true)
+
+    @Test
+    fun isWithinSensorAreaAndNotPaused() = isWithinSensorArea(paused = false)
+
+    private fun isWithinSensorArea(paused: Boolean) {
+        whenever(animationViewController.shouldPauseAuth()).thenReturn(paused)
+        whenever(animationViewController.touchTranslation).thenReturn(PointF(0f, 0f))
+        val end = (SENSOR_RADIUS * 2) - 1
+        for (x in 1 until end) {
+            for (y in 1 until end) {
+                assertThat(view.isWithinSensorArea(x.toFloat(), y.toFloat())).isEqualTo(!paused)
+            }
+        }
+    }
+
+    @Test
+    fun isWithinSensorAreaWhenTranslated() {
+        val offset = PointF(100f, 200f)
+        whenever(animationViewController.touchTranslation).thenReturn(offset)
+        val end = (SENSOR_RADIUS * 2) - 1
+        for (x in 0 until offset.x.toInt() step 2) {
+            for (y in 0 until offset.y.toInt() step 2) {
+                assertThat(view.isWithinSensorArea(x.toFloat(), y.toFloat())).isFalse()
+            }
+        }
+        for (x in offset.x.toInt() + 1 until offset.x.toInt() + end) {
+            for (y in offset.y.toInt() + 1 until offset.y.toInt() + end) {
+                assertThat(view.isWithinSensorArea(x.toFloat(), y.toFloat())).isTrue()
+            }
+        }
+    }
+
+    @Test
+    fun isNotWithinSensorArea() {
+        whenever(animationViewController.touchTranslation).thenReturn(PointF(0f, 0f))
+        assertThat(view.isWithinSensorArea(SENSOR_RADIUS * 2.5f, SENSOR_RADIUS.toFloat())).isFalse()
+        assertThat(view.isWithinSensorArea(SENSOR_RADIUS.toFloat(), SENSOR_RADIUS * 2.5f)).isFalse()
+    }
+
+    @Test
+    fun startAndStopIllumination() {
+        val onDone: Runnable = mock()
+        view.startIllumination(onDone)
+
+        val illuminator = withArgCaptor<Runnable> {
+            verify(hbmProvider).enableHbm(anyInt(), nullable(Surface::class.java), capture())
+        }
+
+        assertThat(view.isIlluminationRequested).isTrue()
+        verify(animationViewController).onIlluminationStarting()
+        verify(animationViewController, never()).onIlluminationStopped()
+        verify(onDone, never()).run()
+
+        // fake illumination event
+        illuminator.run()
+        waitForLooper()
+        verify(onDone).run()
+        verify(hbmProvider, never()).disableHbm(any())
+
+        view.stopIllumination()
+        assertThat(view.isIlluminationRequested).isFalse()
+        verify(animationViewController).onIlluminationStopped()
+        verify(hbmProvider).disableHbm(nullable(Runnable::class.java))
+    }
+
+    private fun waitForLooper() = TestableLooper.get(this).processAllMessages()
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeUiTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeUiTest.java
index 55af51d..e5a75e2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeUiTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeUiTest.java
@@ -27,8 +27,6 @@
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.clearInvocations;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -43,10 +41,7 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.phone.DozeParameters;
-import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.tuner.TunerService;
-import com.android.systemui.unfold.FoldAodAnimationController;
-import com.android.systemui.unfold.SysUIUnfoldComponent;
 import com.android.systemui.util.wakelock.WakeLockFake;
 
 import org.junit.After;
@@ -56,8 +51,6 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
-import java.util.Optional;
-
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class DozeUiTest extends SysuiTestCase {
@@ -82,12 +75,6 @@
     private DozeUi mDozeUi;
     @Mock
     private StatusBarStateController mStatusBarStateController;
-    @Mock
-    private FoldAodAnimationController mFoldAodAnimationController;
-    @Mock
-    private SysUIUnfoldComponent mSysUIUnfoldComponent;
-    @Mock
-    private ConfigurationController mConfigurationController;
 
     @Before
     public void setUp() throws Exception {
@@ -98,13 +85,8 @@
         mWakeLock = new WakeLockFake();
         mHandler = mHandlerThread.getThreadHandler();
 
-        when(mSysUIUnfoldComponent.getFoldAodAnimationController())
-                .thenReturn(mFoldAodAnimationController);
-
         mDozeUi = new DozeUi(mContext, mAlarmManager, mWakeLock, mHost, mHandler,
-                mDozeParameters, mKeyguardUpdateMonitor, mDozeLog, mTunerService,
-                mStatusBarStateController, Optional.of(mSysUIUnfoldComponent),
-                mConfigurationController);
+                mDozeParameters, mKeyguardUpdateMonitor, mStatusBarStateController, mDozeLog);
         mDozeUi.setDozeMachine(mMachine);
     }
 
@@ -116,7 +98,7 @@
     }
 
     @Test
-    public void pausingAndUnpausingAod_registersTimeTickAfterUnpausing() throws Exception {
+    public void pausingAndUnpausingAod_registersTimeTickAfterUnpausing() {
         mDozeUi.transitionTo(UNINITIALIZED, INITIALIZED);
         mDozeUi.transitionTo(INITIALIZED, DOZE_AOD);
         mDozeUi.transitionTo(DOZE_AOD, DOZE_AOD_PAUSED);
@@ -129,60 +111,9 @@
     }
 
     @Test
-    public void propagatesAnimateScreenOff_noAlwaysOn() {
-        reset(mHost);
-        when(mDozeParameters.getAlwaysOn()).thenReturn(false);
-        when(mDozeParameters.getDisplayNeedsBlanking()).thenReturn(false);
-        when(mDozeParameters.shouldAnimateDozingChange()).thenReturn(true);
-
-        mDozeUi.getKeyguardCallback().onKeyguardVisibilityChanged(false);
-        verify(mHost).setAnimateScreenOff(eq(false));
-    }
-
-    @Test
-    public void propagatesAnimateScreenOff_alwaysOn() {
-        reset(mHost);
-        when(mDozeParameters.getAlwaysOn()).thenReturn(true);
-        when(mDozeParameters.getDisplayNeedsBlanking()).thenReturn(false);
-        when(mDozeParameters.shouldAnimateDozingChange()).thenReturn(true);
-
-        // Take over when the keyguard is visible.
-        mDozeUi.getKeyguardCallback().onKeyguardVisibilityChanged(true);
-        verify(mHost).setAnimateScreenOff(eq(true));
-
-        // Do not animate screen-off when keyguard isn't visible - PowerManager will do it.
-        mDozeUi.getKeyguardCallback().onKeyguardVisibilityChanged(false);
-        verify(mHost).setAnimateScreenOff(eq(false));
-    }
-
-    @Test
-    public void propagatesAnimateScreenOff_alwaysOn_shouldAnimateDozingChangeIsFalse() {
-        reset(mHost);
-        when(mDozeParameters.getAlwaysOn()).thenReturn(true);
-        when(mDozeParameters.getDisplayNeedsBlanking()).thenReturn(false);
-        when(mDozeParameters.shouldAnimateDozingChange()).thenReturn(false);
-
-        // Take over when the keyguard is visible.
-        mDozeUi.getKeyguardCallback().onKeyguardVisibilityChanged(true);
-        verify(mHost).setAnimateScreenOff(eq(false));
-    }
-
-    @Test
-    public void neverAnimateScreenOff_whenNotSupported() {
-        // Re-initialize DozeParameters saying that the display requires blanking.
-        reset(mDozeParameters);
-        reset(mHost);
-        when(mDozeParameters.getDisplayNeedsBlanking()).thenReturn(true);
-        mDozeUi = new DozeUi(mContext, mAlarmManager, mWakeLock, mHost, mHandler,
-                mDozeParameters, mKeyguardUpdateMonitor, mDozeLog, mTunerService,
-                mStatusBarStateController, Optional.of(mSysUIUnfoldComponent),
-                mConfigurationController);
-        mDozeUi.setDozeMachine(mMachine);
-
-        // Never animate if display doesn't support it.
-        mDozeUi.getKeyguardCallback().onKeyguardVisibilityChanged(true);
-        mDozeUi.getKeyguardCallback().onKeyguardVisibilityChanged(false);
-        verify(mHost, never()).setAnimateScreenOff(eq(false));
+    public void transitionSetsAnimateWakeup_noAlwaysOn() {
+        mDozeUi.transitionTo(UNINITIALIZED, DOZE);
+        verify(mHost).setAnimateWakeup(eq(false));
     }
 
     @Test
@@ -192,49 +123,4 @@
         mDozeUi.transitionTo(UNINITIALIZED, DOZE);
         verify(mHost).setAnimateWakeup(eq(true));
     }
-
-    @Test
-    public void keyguardVisibility_changesControlScreenOffAnimation() {
-        // Pre-condition
-        reset(mDozeParameters);
-        when(mDozeParameters.getAlwaysOn()).thenReturn(true);
-        when(mDozeParameters.getDisplayNeedsBlanking()).thenReturn(false);
-
-        mDozeUi.getKeyguardCallback().onKeyguardVisibilityChanged(false);
-        verify(mDozeParameters).setControlScreenOffAnimation(eq(false));
-        mDozeUi.getKeyguardCallback().onKeyguardVisibilityChanged(true);
-        verify(mDozeParameters).setControlScreenOffAnimation(eq(true));
-    }
-
-    @Test
-    public void transitionSetsAnimateWakeup_noAlwaysOn() {
-        mDozeUi.transitionTo(UNINITIALIZED, DOZE);
-        verify(mHost).setAnimateWakeup(eq(false));
-    }
-
-    @Test
-    public void controlScreenOffTrueWhenKeyguardNotShowingAndControlUnlockedScreenOff() {
-        when(mDozeParameters.getAlwaysOn()).thenReturn(true);
-        when(mDozeParameters.shouldControlUnlockedScreenOff()).thenReturn(true);
-
-        // Tell doze that keyguard is not visible.
-        mDozeUi.getKeyguardCallback().onKeyguardVisibilityChanged(false /* showing */);
-
-        // Since we're controlling the unlocked screen off animation, verify that we've asked to
-        // control the screen off animation despite being unlocked.
-        verify(mDozeParameters).setControlScreenOffAnimation(true);
-    }
-
-    @Test
-    public void controlScreenOffFalseWhenKeyguardNotShowingAndControlUnlockedScreenOffFalse() {
-        when(mDozeParameters.getAlwaysOn()).thenReturn(true);
-        when(mDozeParameters.shouldControlUnlockedScreenOff()).thenReturn(false);
-
-        // Tell doze that keyguard is not visible.
-        mDozeUi.getKeyguardCallback().onKeyguardVisibilityChanged(false /* showing */);
-
-        // Since we're not controlling the unlocked screen off animation, verify that we haven't
-        // asked to control the screen off animation since we're unlocked.
-        verify(mDozeParameters).setControlScreenOffAnimation(false);
-    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/AppWidgetOverlayProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/ComplicationProviderTest.java
similarity index 84%
rename from packages/SystemUI/tests/src/com/android/systemui/dreams/AppWidgetOverlayProviderTest.java
rename to packages/SystemUI/tests/src/com/android/systemui/dreams/ComplicationProviderTest.java
index 0fc306b..7365568 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/AppWidgetOverlayProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/ComplicationProviderTest.java
@@ -33,8 +33,8 @@
 
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.SysuiTestableContext;
-import com.android.systemui.dreams.appwidgets.AppWidgetOverlayProvider;
 import com.android.systemui.dreams.appwidgets.AppWidgetProvider;
+import com.android.systemui.dreams.appwidgets.ComplicationProvider;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.utils.leaks.LeakCheckedTest;
 
@@ -48,7 +48,7 @@
 
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
-public class AppWidgetOverlayProviderTest extends SysuiTestCase {
+public class ComplicationProviderTest extends SysuiTestCase {
     @Mock
     ActivityStarter mActivityStarter;
 
@@ -62,10 +62,10 @@
     AppWidgetHostView mAppWidgetHostView;
 
     @Mock
-    OverlayHost.CreationCallback mCreationCallback;
+    ComplicationHost.CreationCallback mCreationCallback;
 
     @Mock
-    OverlayHost.InteractionCallback mInteractionCallback;
+    ComplicationHost.InteractionCallback mInteractionCallback;
 
     @Mock
     PendingIntent mPendingIntent;
@@ -73,7 +73,7 @@
     @Mock
     RemoteViews.RemoteResponse mRemoteResponse;
 
-    AppWidgetOverlayProvider mOverlayProvider;
+    ComplicationProvider mComplicationProvider;
 
     RemoteViews.InteractionHandler mInteractionHandler;
 
@@ -84,8 +84,9 @@
     public SysuiTestableContext mContext = new SysuiTestableContext(
             InstrumentationRegistry.getContext(), mLeakCheck);
 
-    OverlayHostView.LayoutParams mLayoutParams = new OverlayHostView.LayoutParams(
-            OverlayHostView.LayoutParams.MATCH_PARENT, OverlayHostView.LayoutParams.MATCH_PARENT);
+    ComplicationHostView.LayoutParams mLayoutParams = new ComplicationHostView.LayoutParams(
+            ComplicationHostView.LayoutParams.MATCH_PARENT,
+            ComplicationHostView.LayoutParams.MATCH_PARENT);
 
     @Before
     public void setup() {
@@ -93,7 +94,7 @@
         when(mPendingIntent.isActivity()).thenReturn(true);
         when(mAppWidgetProvider.getWidget(mComponentName)).thenReturn(mAppWidgetHostView);
 
-        mOverlayProvider = new AppWidgetOverlayProvider(
+        mComplicationProvider = new ComplicationProvider(
                 mActivityStarter,
                 mComponentName,
                 mAppWidgetProvider,
@@ -103,7 +104,8 @@
         final ArgumentCaptor<RemoteViews.InteractionHandler> creationCallbackCapture =
                 ArgumentCaptor.forClass(RemoteViews.InteractionHandler.class);
 
-        mOverlayProvider.onCreateOverlay(mContext, mCreationCallback, mInteractionCallback);
+        mComplicationProvider.onCreateComplication(mContext, mCreationCallback,
+                mInteractionCallback);
         verify(mAppWidgetHostView, times(1))
                 .setInteractionHandler(creationCallbackCapture.capture());
         mInteractionHandler = creationCallbackCapture.getValue();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
new file mode 100644
index 0000000..cf53ccf
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.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.systemui.dreams;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.res.Resources;
+import android.testing.AndroidTestingRunner;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+
+import androidx.constraintlayout.widget.ConstraintLayout;
+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;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class DreamOverlayContainerViewControllerTest extends SysuiTestCase {
+    private static final int DREAM_OVERLAY_NOTIFICATIONS_DRAG_AREA_HEIGHT = 100;
+
+    @Mock
+    Resources mResources;
+
+    @Mock
+    ViewTreeObserver mViewTreeObserver;
+
+    @Mock
+    DreamOverlayStatusBarViewController mDreamOverlayStatusBarViewController;
+
+    @Mock
+    DreamOverlayContainerView mDreamOverlayContainerView;
+
+    @Mock
+    ViewGroup mDreamOverlayContentView;
+
+    DreamOverlayContainerViewController mController;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+
+        when(mResources.getDimensionPixelSize(
+                R.dimen.dream_overlay_notifications_drag_area_height)).thenReturn(
+                        DREAM_OVERLAY_NOTIFICATIONS_DRAG_AREA_HEIGHT);
+        when(mDreamOverlayContainerView.getResources()).thenReturn(mResources);
+        when(mDreamOverlayContainerView.getViewTreeObserver()).thenReturn(mViewTreeObserver);
+
+        mController = new DreamOverlayContainerViewController(
+                mDreamOverlayContainerView, mDreamOverlayContentView,
+                mDreamOverlayStatusBarViewController);
+    }
+
+    @Test
+    public void testDreamOverlayStatusBarViewControllerInitialized() {
+        mController.init();
+        verify(mDreamOverlayStatusBarViewController).init();
+    }
+
+    @Test
+    public void testSetsDreamOverlayNotificationsDragAreaHeight() {
+        assertEquals(
+                mController.getDreamOverlayNotificationsDragAreaHeight(),
+                DREAM_OVERLAY_NOTIFICATIONS_DRAG_AREA_HEIGHT);
+    }
+
+    @Test
+    public void testAddOverlayAddsOverlayToContentView() {
+        View overlay = new View(getContext());
+        ConstraintLayout.LayoutParams layoutParams = new ConstraintLayout.LayoutParams(100, 100);
+        mController.addOverlay(overlay, layoutParams);
+        verify(mDreamOverlayContentView).addView(overlay, layoutParams);
+    }
+
+    @Test
+    public void testRemoveAllOverlaysRemovesOverlaysFromContentView() {
+        mController.removeAllOverlays();
+        verify(mDreamOverlayContentView).removeAllViews();
+    }
+
+    @Test
+    public void testOnViewAttachedRegistersComputeInsetsListener() {
+        mController.onViewAttached();
+        verify(mViewTreeObserver).addOnComputeInternalInsetsListener(any());
+    }
+
+    @Test
+    public void testOnViewDetachedUnregistersComputeInsetsListener() {
+        mController.onViewDetached();
+        verify(mViewTreeObserver).removeOnComputeInternalInsetsListener(any());
+    }
+
+    @Test
+    public void testComputeInsetsListenerReturnsRegion() {
+        final ArgumentCaptor<ViewTreeObserver.OnComputeInternalInsetsListener>
+                computeInsetsListenerCapture =
+                ArgumentCaptor.forClass(ViewTreeObserver.OnComputeInternalInsetsListener.class);
+        mController.onViewAttached();
+        verify(mViewTreeObserver).addOnComputeInternalInsetsListener(
+                computeInsetsListenerCapture.capture());
+        final ViewTreeObserver.InternalInsetsInfo info = new ViewTreeObserver.InternalInsetsInfo();
+        computeInsetsListenerCapture.getValue().onComputeInternalInsets(info);
+        assertNotNull(info.touchableRegion);
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java
index 904ee91..8cd8e4d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java
@@ -17,7 +17,6 @@
 package com.android.systemui.dreams;
 
 import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -55,8 +54,8 @@
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 public class DreamOverlayServiceTest extends SysuiTestCase {
-    private FakeSystemClock mFakeSystemClock = new FakeSystemClock();
-    private FakeExecutor mMainExecutor = new FakeExecutor(mFakeSystemClock);
+    private final FakeSystemClock mFakeSystemClock = new FakeSystemClock();
+    private final FakeExecutor mMainExecutor = new FakeExecutor(mFakeSystemClock);
 
     @Rule
     public final LeakCheckedTest.SysuiLeakCheck mLeakCheck = new LeakCheckedTest.SysuiLeakCheck();
@@ -74,74 +73,95 @@
     WindowManagerImpl mWindowManager;
 
     @Mock
-    OverlayProvider mProvider;
+    ComplicationProvider mProvider;
 
     @Mock
     DreamOverlayStateController mDreamOverlayStateController;
 
     @Mock
-    DreamOverlayComponent.Factory mDreamOverlayStatusBarViewComponentFactory;
+    DreamOverlayComponent.Factory mDreamOverlayComponentFactory;
 
     @Mock
     DreamOverlayComponent mDreamOverlayComponent;
 
     @Mock
-    DreamOverlayStatusBarViewController mDreamOverlayStatusBarViewController;
-
-    @Mock
     DreamOverlayContainerView mDreamOverlayContainerView;
 
     @Mock
-    ViewGroup mDreamOverlayContentView;
+    DreamOverlayContainerViewController mDreamOverlayContainerViewController;
+
+    DreamOverlayService mService;
 
     @Before
-    public void setup() {
+    public void setup() throws Exception {
         MockitoAnnotations.initMocks(this);
         mContext.addMockSystemService(WindowManager.class, mWindowManager);
 
-        when(mDreamOverlayComponent.getDreamOverlayContentView())
-                .thenReturn(mDreamOverlayContentView);
-        when(mDreamOverlayComponent.getDreamOverlayContainerView())
-                .thenReturn(mDreamOverlayContainerView);
-        when(mDreamOverlayComponent.getDreamOverlayStatusBarViewController())
-                .thenReturn(mDreamOverlayStatusBarViewController);
-        when(mDreamOverlayStatusBarViewComponentFactory.create())
+        when(mDreamOverlayComponent.getDreamOverlayContainerViewController())
+                .thenReturn(mDreamOverlayContainerViewController);
+        when(mDreamOverlayComponentFactory.create())
                 .thenReturn(mDreamOverlayComponent);
+        when(mDreamOverlayContainerViewController.getContainerView())
+                .thenReturn(mDreamOverlayContainerView);
 
-    }
-
-    @Test
-    public void testInteraction() throws Exception {
-        final DreamOverlayService service = new DreamOverlayService(mContext, mMainExecutor,
-                mDreamOverlayStateController, mDreamOverlayStatusBarViewComponentFactory);
-        final IBinder proxy = service.onBind(new Intent());
+        mService = new DreamOverlayService(mContext, mMainExecutor,
+                mDreamOverlayStateController, mDreamOverlayComponentFactory);
+        final IBinder proxy = mService.onBind(new Intent());
         final IDreamOverlay overlay = IDreamOverlay.Stub.asInterface(proxy);
-        clearInvocations(mWindowManager);
 
         // Inform the overlay service of dream starting.
         overlay.startDream(mWindowParams, mDreamOverlayCallback);
         mMainExecutor.runAllReady();
-        verify(mWindowManager).addView(any(), any());
+    }
 
+    @Test
+    public void testOverlayContainerViewAddedToWindow() {
+        verify(mWindowManager).addView(any(), any());
+    }
+
+    @Test
+    public void testDreamOverlayContainerViewControllerInitialized() {
+        verify(mDreamOverlayContainerViewController).init();
+    }
+
+    @Test
+    public void testAddingOverlayToDream() throws Exception {
         // Add overlay.
-        service.addOverlay(mProvider);
+        mService.addComplication(mProvider);
         mMainExecutor.runAllReady();
 
-        final ArgumentCaptor<OverlayHost.CreationCallback> creationCallbackCapture =
-                ArgumentCaptor.forClass(OverlayHost.CreationCallback.class);
-        final ArgumentCaptor<OverlayHost.InteractionCallback> interactionCallbackCapture =
-                ArgumentCaptor.forClass(OverlayHost.InteractionCallback.class);
+        final ArgumentCaptor<ComplicationHost.CreationCallback> creationCallbackCapture =
+                ArgumentCaptor.forClass(ComplicationHost.CreationCallback.class);
+        final ArgumentCaptor<ComplicationHost.InteractionCallback> interactionCallbackCapture =
+                ArgumentCaptor.forClass(ComplicationHost.InteractionCallback.class);
 
         // Ensure overlay provider is asked to create view.
-        verify(mProvider).onCreateOverlay(any(), creationCallbackCapture.capture(),
+        verify(mProvider).onCreateComplication(any(), creationCallbackCapture.capture(),
                 interactionCallbackCapture.capture());
         mMainExecutor.runAllReady();
 
         // Inform service of overlay view creation.
         final View view = new View(mContext);
-        creationCallbackCapture.getValue().onCreated(view, new ConstraintLayout.LayoutParams(
+        final ConstraintLayout.LayoutParams lp = new ConstraintLayout.LayoutParams(
                 ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT
-        ));
+        );
+        creationCallbackCapture.getValue().onCreated(view, lp);
+        mMainExecutor.runAllReady();
+
+        // Verify that DreamOverlayContainerViewController is asked to add an overlay for the view.
+        verify(mDreamOverlayContainerViewController).addOverlay(view, lp);
+    }
+
+    @Test
+    public void testDreamOverlayExit() throws Exception {
+        // Add overlay.
+        mService.addComplication(mProvider);
+        mMainExecutor.runAllReady();
+
+        // Capture interaction callback from overlay creation.
+        final ArgumentCaptor<ComplicationHost.InteractionCallback> interactionCallbackCapture =
+                ArgumentCaptor.forClass(ComplicationHost.InteractionCallback.class);
+        verify(mProvider).onCreateComplication(any(), any(), interactionCallbackCapture.capture());
 
         // Ask service to exit.
         interactionCallbackCapture.getValue().onExit();
@@ -152,59 +172,27 @@
     }
 
     @Test
-    public void testListening() throws Exception {
-        final DreamOverlayService service = new DreamOverlayService(mContext, mMainExecutor,
-                mDreamOverlayStateController, mDreamOverlayStatusBarViewComponentFactory);
-
-        final IBinder proxy = service.onBind(new Intent());
-        final IDreamOverlay overlay = IDreamOverlay.Stub.asInterface(proxy);
-
-        // Inform the overlay service of dream starting.
-        overlay.startDream(mWindowParams, mDreamOverlayCallback);
-        mMainExecutor.runAllReady();
-
+    public void testListenerRegisteredWithDreamOverlayStateController() {
         // Verify overlay service registered as listener with DreamOverlayStateController
         // and inform callback of addition.
         final ArgumentCaptor<DreamOverlayStateController.Callback> callbackCapture =
                 ArgumentCaptor.forClass(DreamOverlayStateController.Callback.class);
 
         verify(mDreamOverlayStateController).addCallback(callbackCapture.capture());
-        when(mDreamOverlayStateController.getOverlays()).thenReturn(Arrays.asList(mProvider));
-        callbackCapture.getValue().onOverlayChanged();
+        when(mDreamOverlayStateController.getComplications()).thenReturn(Arrays.asList(mProvider));
+        callbackCapture.getValue().onComplicationsChanged();
         mMainExecutor.runAllReady();
 
         // Verify provider is asked to create overlay.
-        verify(mProvider).onCreateOverlay(any(), any(), any());
+        verify(mProvider).onCreateComplication(any(), any(), any());
     }
 
     @Test
-    public void testDreamOverlayStatusBarViewControllerInitialized() throws Exception {
-        final DreamOverlayService service = new DreamOverlayService(mContext, mMainExecutor,
-                mDreamOverlayStateController, mDreamOverlayStatusBarViewComponentFactory);
-
-        final IBinder proxy = service.onBind(new Intent());
-        final IDreamOverlay overlay = IDreamOverlay.Stub.asInterface(proxy);
-
-        // Inform the overlay service of dream starting.
-        overlay.startDream(mWindowParams, mDreamOverlayCallback);
-        mMainExecutor.runAllReady();
-
-        verify(mDreamOverlayStatusBarViewController).init();
-    }
-
-    @Test
-    public void testRootViewAttachListenerIsAddedToDreamOverlayContentView() throws Exception {
-        final DreamOverlayService service = new DreamOverlayService(mContext, mMainExecutor,
-                mDreamOverlayStateController, mDreamOverlayStatusBarViewComponentFactory);
-
-        final IBinder proxy = service.onBind(new Intent());
-        final IDreamOverlay overlay = IDreamOverlay.Stub.asInterface(proxy);
-
-        // Inform the overlay service of dream starting.
-        overlay.startDream(mWindowParams, mDreamOverlayCallback);
-        mMainExecutor.runAllReady();
-
-        verify(mDreamOverlayContentView).addOnAttachStateChangeListener(
-                any(View.OnAttachStateChangeListener.class));
+    public void testOnDestroyRemovesOverlayStateCallback() {
+        final ArgumentCaptor<DreamOverlayStateController.Callback> callbackCapture =
+                ArgumentCaptor.forClass(DreamOverlayStateController.Callback.class);
+        verify(mDreamOverlayStateController).addCallback(callbackCapture.capture());
+        mService.onDestroy();
+        verify(mDreamOverlayStateController).removeCallback(callbackCapture.getValue());
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java
index 4e97be3..efc3c7c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java
@@ -27,6 +27,10 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.time.FakeSystemClock;
+
+import com.google.common.util.concurrent.ListenableFuture;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -43,7 +47,9 @@
     DreamOverlayStateController.Callback mCallback;
 
     @Mock
-    OverlayProvider mProvider;
+    ComplicationProvider mProvider;
+
+    final FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
 
     @Before
     public void setup() {
@@ -51,36 +57,43 @@
     }
 
     @Test
-    public void testCallback() {
-        final DreamOverlayStateController stateController = new DreamOverlayStateController();
+    public void testCallback() throws Exception {
+        final DreamOverlayStateController stateController = new DreamOverlayStateController(
+                mExecutor);
         stateController.addCallback(mCallback);
 
-        // Add overlay and verify callback is notified.
-        final DreamOverlayStateController.OverlayToken token =
-                stateController.addOverlay(mProvider);
+        // Add complication and verify callback is notified.
+        final ListenableFuture<DreamOverlayStateController.ComplicationToken> tokenFuture =
+                stateController.addComplication(mProvider);
 
-        verify(mCallback, times(1)).onOverlayChanged();
+        mExecutor.runAllReady();
 
-        final Collection<OverlayProvider> providers = stateController.getOverlays();
+        verify(mCallback, times(1)).onComplicationsChanged();
+
+        final Collection<ComplicationProvider> providers = stateController.getComplications();
         assertEquals(providers.size(), 1);
         assertTrue(providers.contains(mProvider));
 
         clearInvocations(mCallback);
 
-        // Remove overlay and verify callback is notified.
-        stateController.removeOverlay(token);
-        verify(mCallback, times(1)).onOverlayChanged();
+        // Remove complication and verify callback is notified.
+        stateController.removeComplication(tokenFuture.get());
+        mExecutor.runAllReady();
+        verify(mCallback, times(1)).onComplicationsChanged();
         assertTrue(providers.isEmpty());
     }
 
     @Test
     public void testNotifyOnCallbackAdd() {
-        final DreamOverlayStateController stateController = new DreamOverlayStateController();
-        final DreamOverlayStateController.OverlayToken token =
-                stateController.addOverlay(mProvider);
+        final DreamOverlayStateController stateController =
+                new DreamOverlayStateController(mExecutor);
+
+        stateController.addComplication(mProvider);
+        mExecutor.runAllReady();
 
         // Verify callback occurs on add when an overlay is already present.
         stateController.addCallback(mCallback);
-        verify(mCallback, times(1)).onOverlayChanged();
+        mExecutor.runAllReady();
+        verify(mCallback, times(1)).onComplicationsChanged();
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/appwidgets/AppWidgetOverlayPrimerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/appwidgets/ComplicationPrimerTest.java
similarity index 61%
rename from packages/SystemUI/tests/src/com/android/systemui/dreams/appwidgets/AppWidgetOverlayPrimerTest.java
rename to packages/SystemUI/tests/src/com/android/systemui/dreams/appwidgets/ComplicationPrimerTest.java
index 2e5b165..adf110b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/appwidgets/AppWidgetOverlayPrimerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/appwidgets/ComplicationPrimerTest.java
@@ -37,7 +37,7 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.SysuiTestableContext;
 import com.android.systemui.dreams.DreamOverlayStateController;
-import com.android.systemui.dreams.dagger.AppWidgetOverlayComponent;
+import com.android.systemui.dreams.appwidgets.dagger.AppWidgetComponent;
 import com.android.systemui.utils.leaks.LeakCheckedTest;
 
 import org.junit.Before;
@@ -50,7 +50,7 @@
 
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
-public class AppWidgetOverlayPrimerTest extends SysuiTestCase {
+public class ComplicationPrimerTest extends SysuiTestCase {
     @Rule
     public final LeakCheckedTest.SysuiLeakCheck mLeakCheck = new LeakCheckedTest.SysuiLeakCheck();
 
@@ -62,56 +62,57 @@
     Resources mResources;
 
     @Mock
-    AppWidgetOverlayComponent mAppWidgetOverlayComponent1;
+    AppWidgetComponent mAppWidgetComplicationComponent1;
     @Mock
-    AppWidgetOverlayComponent mAppWidgetOverlayComponent2;
+    AppWidgetComponent mAppWidgetComplicationComponent2;
 
     @Mock
-    AppWidgetOverlayProvider mAppWidgetOverlayProvider1;
+    ComplicationProvider mComplicationProvider1;
 
     @Mock
-    AppWidgetOverlayProvider mAppWidgetOverlayProvider2;
+    ComplicationProvider mComplicationProvider2;
 
-    final ComponentName mAppOverlayComponent1 =
+    final ComponentName mAppComplicationComponent1 =
             ComponentName.unflattenFromString("com.foo.bar/.Baz");
-    final ComponentName mAppOverlayComponent2 =
+    final ComponentName mAppComplicationComponent2 =
             ComponentName.unflattenFromString("com.foo.bar/.Baz2");
 
-    final int mAppOverlayGravity1 = Gravity.BOTTOM | Gravity.START;
-    final int mAppOverlayGravity2 = Gravity.BOTTOM | Gravity.END;
+    final int mAppComplicationGravity1 = Gravity.BOTTOM | Gravity.START;
+    final int mAppComplicationGravity2 = Gravity.BOTTOM | Gravity.END;
 
-    final String[] mComponents = new String[]{mAppOverlayComponent1.flattenToString(),
-            mAppOverlayComponent2.flattenToString() };
-    final int[] mPositions = new int[]{ mAppOverlayGravity1, mAppOverlayGravity2 };
+    final String[] mComponents = new String[]{mAppComplicationComponent1.flattenToString(),
+            mAppComplicationComponent2.flattenToString() };
+    final int[] mPositions = new int[]{mAppComplicationGravity1, mAppComplicationGravity2};
 
     @Mock
     DreamOverlayStateController mDreamOverlayStateController;
 
     @Mock
-    AppWidgetOverlayComponent.Factory mAppWidgetOverlayProviderFactory;
+    AppWidgetComponent.Factory mAppWidgetComplicationProviderFactory;
 
     @Before
     public void setup() {
         MockitoAnnotations.initMocks(this);
-        when(mAppWidgetOverlayProviderFactory.build(eq(mAppOverlayComponent1), any()))
-                .thenReturn(mAppWidgetOverlayComponent1);
-        when(mAppWidgetOverlayComponent1.getAppWidgetOverlayProvider())
-                .thenReturn(mAppWidgetOverlayProvider1);
-        when(mAppWidgetOverlayProviderFactory.build(eq(mAppOverlayComponent2), any()))
-                .thenReturn(mAppWidgetOverlayComponent2);
-        when(mAppWidgetOverlayComponent2.getAppWidgetOverlayProvider())
-                .thenReturn(mAppWidgetOverlayProvider2);
-        when(mResources.getIntArray(R.array.config_dreamOverlayPositions)).thenReturn(mPositions);
-        when(mResources.getStringArray(R.array.config_dreamOverlayComponents))
+        when(mAppWidgetComplicationProviderFactory.build(eq(mAppComplicationComponent1), any()))
+                .thenReturn(mAppWidgetComplicationComponent1);
+        when(mAppWidgetComplicationComponent1.getAppWidgetComplicationProvider())
+                .thenReturn(mComplicationProvider1);
+        when(mAppWidgetComplicationProviderFactory.build(eq(mAppComplicationComponent2), any()))
+                .thenReturn(mAppWidgetComplicationComponent2);
+        when(mAppWidgetComplicationComponent2.getAppWidgetComplicationProvider())
+                .thenReturn(mComplicationProvider2);
+        when(mResources.getIntArray(R.array.config_dreamComplicationPositions))
+                .thenReturn(mPositions);
+        when(mResources.getStringArray(R.array.config_dreamAppWidgetComplications))
                 .thenReturn(mComponents);
     }
 
     @Test
     public void testLoading() {
-        final AppWidgetOverlayPrimer primer = new AppWidgetOverlayPrimer(mContext,
+        final ComplicationPrimer primer = new ComplicationPrimer(mContext,
                 mResources,
                 mDreamOverlayStateController,
-                mAppWidgetOverlayProviderFactory);
+                mAppWidgetComplicationProviderFactory);
 
         // Inform primer to begin.
         primer.onBootCompleted();
@@ -120,7 +121,8 @@
         {
             final ArgumentCaptor<ConstraintLayout.LayoutParams> layoutParamsArgumentCaptor =
                     ArgumentCaptor.forClass(ConstraintLayout.LayoutParams.class);
-            verify(mAppWidgetOverlayProviderFactory, times(1)).build(eq(mAppOverlayComponent1),
+            verify(mAppWidgetComplicationProviderFactory, times(1))
+                    .build(eq(mAppComplicationComponent1),
                     layoutParamsArgumentCaptor.capture());
 
             assertEquals(layoutParamsArgumentCaptor.getValue().startToStart,
@@ -129,14 +131,15 @@
                     ConstraintLayout.LayoutParams.PARENT_ID);
 
             verify(mDreamOverlayStateController, times(1))
-                    .addOverlay(eq(mAppWidgetOverlayProvider1));
+                    .addComplication(eq(mComplicationProvider1));
         }
 
         // Verify the second component is added to the state controller with the proper position.
         {
             final ArgumentCaptor<ConstraintLayout.LayoutParams> layoutParamsArgumentCaptor =
                     ArgumentCaptor.forClass(ConstraintLayout.LayoutParams.class);
-            verify(mAppWidgetOverlayProviderFactory, times(1)).build(eq(mAppOverlayComponent2),
+            verify(mAppWidgetComplicationProviderFactory, times(1))
+                    .build(eq(mAppComplicationComponent2),
                     layoutParamsArgumentCaptor.capture());
 
             assertEquals(layoutParamsArgumentCaptor.getValue().endToEnd,
@@ -144,19 +147,19 @@
             assertEquals(layoutParamsArgumentCaptor.getValue().bottomToBottom,
                     ConstraintLayout.LayoutParams.PARENT_ID);
             verify(mDreamOverlayStateController, times(1))
-                    .addOverlay(eq(mAppWidgetOverlayProvider1));
+                    .addComplication(eq(mComplicationProvider1));
         }
     }
 
     @Test
     public void testNoComponents() {
-        when(mResources.getStringArray(R.array.config_dreamOverlayComponents))
+        when(mResources.getStringArray(R.array.config_dreamAppWidgetComplications))
                 .thenReturn(new String[]{});
 
-        final AppWidgetOverlayPrimer primer = new AppWidgetOverlayPrimer(mContext,
+        final ComplicationPrimer primer = new ComplicationPrimer(mContext,
                 mResources,
                 mDreamOverlayStateController,
-                mAppWidgetOverlayProviderFactory);
+                mAppWidgetComplicationProviderFactory);
 
         // Inform primer to begin.
         primer.onBootCompleted();
@@ -164,25 +167,25 @@
 
         // Make sure there is no request to add a widget if no components are specified by the
         // product.
-        verify(mAppWidgetOverlayProviderFactory, never()).build(any(), any());
-        verify(mDreamOverlayStateController, never()).addOverlay(any());
+        verify(mAppWidgetComplicationProviderFactory, never()).build(any(), any());
+        verify(mDreamOverlayStateController, never()).addComplication(any());
     }
 
     @Test
     public void testNoPositions() {
-        when(mResources.getIntArray(R.array.config_dreamOverlayPositions))
+        when(mResources.getIntArray(R.array.config_dreamComplicationPositions))
                 .thenReturn(new int[]{});
 
-        final AppWidgetOverlayPrimer primer = new AppWidgetOverlayPrimer(mContext,
+        final ComplicationPrimer primer = new ComplicationPrimer(mContext,
                 mResources,
                 mDreamOverlayStateController,
-                mAppWidgetOverlayProviderFactory);
+                mAppWidgetComplicationProviderFactory);
 
         primer.onBootCompleted();
 
         // Make sure there is no request to add a widget if no positions are specified by the
         // product.
-        verify(mAppWidgetOverlayProviderFactory, never()).build(any(), any());
-        verify(mDreamOverlayStateController, never()).addOverlay(any());
+        verify(mAppWidgetComplicationProviderFactory, never()).build(any(), any());
+        verify(mDreamOverlayStateController, never()).addComplication(any());
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
index 27fcb11..9827d21 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -34,7 +34,6 @@
 import android.app.trust.TrustManager;
 import android.os.PowerManager;
 import android.os.PowerManager.WakeLock;
-import android.os.RemoteException;
 import android.telephony.TelephonyManager;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
@@ -42,10 +41,10 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.jank.InteractionJankMonitor;
-import com.android.internal.policy.IKeyguardDrawnCallback;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.KeyguardDisplayManager;
 import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.keyguard.mediator.ScreenOnCoordinator;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.classifier.FalsingCollectorFake;
@@ -58,9 +57,6 @@
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
-import com.android.systemui.unfold.FoldAodAnimationController;
-import com.android.systemui.unfold.SysUIUnfoldComponent;
-import com.android.systemui.unfold.UnfoldLightRevealOverlayAnimation;
 import com.android.systemui.util.DeviceConfigProxy;
 import com.android.systemui.util.DeviceConfigProxyFake;
 import com.android.systemui.util.concurrency.FakeExecutor;
@@ -69,13 +65,9 @@
 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.Optional;
-import java.util.function.Function;
-
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper
 @SmallTest
@@ -95,36 +87,25 @@
     private @Mock NavigationModeController mNavigationModeController;
     private @Mock KeyguardDisplayManager mKeyguardDisplayManager;
     private @Mock DozeParameters mDozeParameters;
-    private @Mock SysUIUnfoldComponent mSysUIUnfoldComponent;
-    private @Mock UnfoldLightRevealOverlayAnimation mUnfoldAnimation;
     private @Mock SysuiStatusBarStateController mStatusBarStateController;
     private @Mock KeyguardStateController mKeyguardStateController;
     private @Mock NotificationShadeDepthController mNotificationShadeDepthController;
     private @Mock KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
     private @Mock ScreenOffAnimationController mScreenOffAnimationController;
-    private @Mock FoldAodAnimationController mFoldAodAnimationController;
-    private @Mock IKeyguardDrawnCallback mKeyguardDrawnCallback;
     private @Mock InteractionJankMonitor mInteractionJankMonitor;
+    private @Mock ScreenOnCoordinator mScreenOnCoordinator;
     private DeviceConfigProxy mDeviceConfig = new DeviceConfigProxyFake();
     private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
 
-    private Optional<SysUIUnfoldComponent> mSysUiUnfoldComponentOptional;
-
     private FalsingCollectorFake mFalsingCollector;
 
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
         mFalsingCollector = new FalsingCollectorFake();
-        mSysUiUnfoldComponentOptional = Optional.of(mSysUIUnfoldComponent);
 
         when(mLockPatternUtils.getDevicePolicyManager()).thenReturn(mDevicePolicyManager);
         when(mPowerManager.newWakeLock(anyInt(), any())).thenReturn(mock(WakeLock.class));
-        when(mSysUIUnfoldComponent.getUnfoldLightRevealOverlayAnimation())
-                .thenReturn(mUnfoldAnimation);
-        when(mSysUIUnfoldComponent.getFoldAodAnimationController())
-                .thenReturn(mFoldAodAnimationController);
-
         when(mInteractionJankMonitor.begin(any(), anyInt())).thenReturn(true);
         when(mInteractionJankMonitor.end(anyInt())).thenReturn(true);
 
@@ -151,33 +132,6 @@
     }
 
     @Test
-    @TestableLooper.RunWithLooper(setAsMainLooper = true)
-    public void testUnfoldTransitionEnabledDrawnTasksReady_onScreenTurningOn_callsDrawnCallback()
-            throws RemoteException {
-        mViewMediator.onScreenTurningOn(mKeyguardDrawnCallback);
-        TestableLooper.get(this).processAllMessages();
-        onUnfoldOverlayReady();
-        onFoldAodReady();
-
-        // Should be called when both unfold overlay and keyguard drawn ready
-        verify(mKeyguardDrawnCallback).onDrawn();
-    }
-
-    @Test
-    @TestableLooper.RunWithLooper(setAsMainLooper = true)
-    public void testUnfoldTransitionDisabledDrawnTasksReady_onScreenTurningOn_callsDrawnCallback()
-            throws RemoteException {
-        mSysUiUnfoldComponentOptional = Optional.empty();
-        createAndStartViewMediator();
-
-        mViewMediator.onScreenTurningOn(mKeyguardDrawnCallback);
-        TestableLooper.get(this).processAllMessages();
-
-        // Should be called when only keyguard drawn
-        verify(mKeyguardDrawnCallback).onDrawn();
-    }
-
-    @Test
     public void testIsAnimatingScreenOff() {
         when(mDozeParameters.shouldControlUnlockedScreenOff()).thenReturn(true);
         when(mDozeParameters.shouldAnimateDozingChange()).thenReturn(true);
@@ -219,20 +173,6 @@
         verify(mStatusBarKeyguardViewManager, atLeast(1)).show(null);
     }
 
-    private void onUnfoldOverlayReady() {
-        ArgumentCaptor<Runnable> overlayReadyCaptor = ArgumentCaptor.forClass(Runnable.class);
-        verify(mUnfoldAnimation).onScreenTurningOn(overlayReadyCaptor.capture());
-        overlayReadyCaptor.getValue().run();
-        TestableLooper.get(this).processAllMessages();
-    }
-
-    private void onFoldAodReady() {
-        ArgumentCaptor<Runnable> ready = ArgumentCaptor.forClass(Runnable.class);
-        verify(mFoldAodAnimationController).onScreenTurningOn(ready.capture());
-        ready.getValue().run();
-        TestableLooper.get(this).processAllMessages();
-    }
-
     private void createAndStartViewMediator() {
         mViewMediator = new KeyguardViewMediator(
                 mContext,
@@ -251,12 +191,12 @@
                 mNavigationModeController,
                 mKeyguardDisplayManager,
                 mDozeParameters,
-                mSysUiUnfoldComponentOptional,
                 mStatusBarStateController,
                 mKeyguardStateController,
                 () -> mKeyguardUnlockAnimationController,
                 mScreenOffAnimationController,
                 () -> mNotificationShadeDepthController,
+                mScreenOnCoordinator,
                 mInteractionJankMonitor);
         mViewMediator.start();
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ScreenLifecycleTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ScreenLifecycleTest.java
index 2d1b258..53d0dd8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ScreenLifecycleTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ScreenLifecycleTest.java
@@ -57,15 +57,16 @@
 
     @Test
     public void screenTurningOn() throws Exception {
-        mScreen.dispatchScreenTurningOn();
+        Runnable onDrawn = () -> {};
+        mScreen.dispatchScreenTurningOn(onDrawn);
 
         assertEquals(ScreenLifecycle.SCREEN_TURNING_ON, mScreen.getScreenState());
-        verify(mScreenObserverMock).onScreenTurningOn();
+        verify(mScreenObserverMock).onScreenTurningOn(onDrawn);
     }
 
     @Test
     public void screenTurnedOn() throws Exception {
-        mScreen.dispatchScreenTurningOn();
+        mScreen.dispatchScreenTurningOn(null);
         mScreen.dispatchScreenTurnedOn();
 
         assertEquals(ScreenLifecycle.SCREEN_ON, mScreen.getScreenState());
@@ -74,7 +75,7 @@
 
     @Test
     public void screenTurningOff() throws Exception {
-        mScreen.dispatchScreenTurningOn();
+        mScreen.dispatchScreenTurningOn(null);
         mScreen.dispatchScreenTurnedOn();
         mScreen.dispatchScreenTurningOff();
 
@@ -84,7 +85,7 @@
 
     @Test
     public void screenTurnedOff() throws Exception {
-        mScreen.dispatchScreenTurningOn();
+        mScreen.dispatchScreenTurningOn(null);
         mScreen.dispatchScreenTurnedOn();
         mScreen.dispatchScreenTurningOff();
         mScreen.dispatchScreenTurnedOff();
@@ -97,4 +98,4 @@
     public void dump() throws Exception {
         mScreen.dump(null, new PrintWriter(new ByteArrayOutputStream()), new String[0]);
     }
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt
index a6e567e..d2be1f4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt
@@ -36,6 +36,7 @@
 import org.junit.runner.RunWith
 import org.mockito.Mock
 import org.mockito.MockitoAnnotations
+import org.mockito.Mockito.`when` as whenever
 import javax.inject.Provider
 
 private val DATA = MediaData(
@@ -74,6 +75,7 @@
     @Mock lateinit var falsingCollector: FalsingCollector
     @Mock lateinit var falsingManager: FalsingManager
     @Mock lateinit var dumpManager: DumpManager
+    @Mock lateinit var mediaFlags: MediaFlags
 
     private val clock = FakeSystemClock()
     private lateinit var mediaCarouselController: MediaCarouselController
@@ -81,7 +83,7 @@
     @Before
     fun setup() {
         MockitoAnnotations.initMocks(this)
-
+        whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(true)
         mediaCarouselController = MediaCarouselController(
             context,
             mediaControlPanelFactory,
@@ -94,7 +96,8 @@
             configurationController,
             falsingCollector,
             falsingManager,
-            dumpManager
+            dumpManager,
+            mediaFlags
         )
 
         MediaPlayerData.clear()
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 7cc0172..7763e75 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
@@ -43,7 +43,6 @@
 import com.android.systemui.media.dialog.MediaOutputDialogFactory
 import com.android.systemui.plugins.ActivityStarter
 import com.android.systemui.plugins.FalsingManager
-import com.android.systemui.statusbar.phone.KeyguardDismissUtil
 import com.android.systemui.util.animation.TransitionLayout
 import com.android.systemui.util.concurrency.FakeExecutor
 import com.android.systemui.util.mockito.eq
@@ -87,11 +86,11 @@
     @Mock private lateinit var activityStarter: ActivityStarter
 
     @Mock private lateinit var holder: PlayerViewHolder
+    @Mock private lateinit var sessionHolder: PlayerSessionViewHolder
     @Mock private lateinit var view: TransitionLayout
     @Mock private lateinit var seekBarViewModel: SeekBarViewModel
     @Mock private lateinit var seekBarData: LiveData<SeekBarViewModel.Progress>
     @Mock private lateinit var mediaViewController: MediaViewController
-    @Mock private lateinit var keyguardDismissUtil: KeyguardDismissUtil
     @Mock private lateinit var mediaDataManager: MediaDataManager
     @Mock private lateinit var expandedSet: ConstraintSet
     @Mock private lateinit var collapsedSet: ConstraintSet
@@ -104,6 +103,8 @@
     private lateinit var titleText: TextView
     private lateinit var artistText: TextView
     private lateinit var seamless: ViewGroup
+    private lateinit var seamlessButton: View
+    @Mock private lateinit var seamlessBackground: RippleDrawable
     private lateinit var seamlessIcon: ImageView
     private lateinit var seamlessText: TextView
     private lateinit var seekBar: SeekBar
@@ -114,6 +115,11 @@
     private lateinit var action2: ImageButton
     private lateinit var action3: ImageButton
     private lateinit var action4: ImageButton
+    private lateinit var actionPlayPause: ImageButton
+    private lateinit var actionNext: ImageButton
+    private lateinit var actionPrev: ImageButton
+    private lateinit var actionStart: ImageButton
+    private lateinit var actionEnd: ImageButton
     @Mock private lateinit var longPressText: TextView
     @Mock private lateinit var handler: Handler
     private lateinit var settings: View
@@ -137,62 +143,30 @@
         whenever(mediaViewController.collapsedLayout).thenReturn(collapsedSet)
 
         player = MediaControlPanel(context, bgExecutor, activityStarter, mediaViewController,
-            seekBarViewModel, Lazy { mediaDataManager }, keyguardDismissUtil,
+            seekBarViewModel, Lazy { mediaDataManager },
             mediaOutputDialogFactory, mediaCarouselController, falsingManager, mediaFlags, clock)
         whenever(seekBarViewModel.progress).thenReturn(seekBarData)
 
-        // Mock out a view holder for the player to attach to.
-        whenever(holder.player).thenReturn(view)
+        // Set up mock views for the players
         appIcon = ImageView(context)
-        whenever(holder.appIcon).thenReturn(appIcon)
         albumView = ImageView(context)
-        whenever(holder.albumView).thenReturn(albumView)
         titleText = TextView(context)
-        whenever(holder.titleText).thenReturn(titleText)
         artistText = TextView(context)
-        whenever(holder.artistText).thenReturn(artistText)
         seamless = FrameLayout(context)
-        val seamlessBackground = mock(RippleDrawable::class.java)
         seamless.foreground = seamlessBackground
-        whenever(seamlessBackground.getDrawable(0)).thenReturn(mock(GradientDrawable::class.java))
-        whenever(holder.seamless).thenReturn(seamless)
+        seamlessButton = View(context)
         seamlessIcon = ImageView(context)
-        whenever(holder.seamlessIcon).thenReturn(seamlessIcon)
         seamlessText = TextView(context)
-        whenever(holder.seamlessText).thenReturn(seamlessText)
         seekBar = SeekBar(context)
-        whenever(holder.seekBar).thenReturn(seekBar)
         elapsedTimeView = TextView(context)
-        whenever(holder.elapsedTimeView).thenReturn(elapsedTimeView)
         totalTimeView = TextView(context)
-        whenever(holder.totalTimeView).thenReturn(totalTimeView)
-        action0 = ImageButton(context)
-        whenever(holder.action0).thenReturn(action0)
-        whenever(holder.getAction(R.id.action0)).thenReturn(action0)
-        action1 = ImageButton(context)
-        whenever(holder.action1).thenReturn(action1)
-        whenever(holder.getAction(R.id.action1)).thenReturn(action1)
-        action2 = ImageButton(context)
-        whenever(holder.action2).thenReturn(action2)
-        whenever(holder.getAction(R.id.action2)).thenReturn(action2)
-        action3 = ImageButton(context)
-        whenever(holder.action3).thenReturn(action3)
-        whenever(holder.getAction(R.id.action3)).thenReturn(action3)
-        action4 = ImageButton(context)
-        whenever(holder.action4).thenReturn(action4)
-        whenever(holder.getAction(R.id.action4)).thenReturn(action4)
-        whenever(holder.longPressText).thenReturn(longPressText)
-        whenever(longPressText.handler).thenReturn(handler)
         settings = View(context)
-        whenever(holder.settings).thenReturn(settings)
         settingsText = TextView(context)
-        whenever(holder.settingsText).thenReturn(settingsText)
         cancel = View(context)
-        whenever(holder.cancel).thenReturn(cancel)
         dismiss = FrameLayout(context)
-        whenever(holder.dismiss).thenReturn(dismiss)
         dismissLabel = View(context)
-        whenever(holder.dismissLabel).thenReturn(dismissLabel)
+        initPlayerHolderMocks()
+        initSessionHolderMocks()
 
         // Create media session
         val metadataBuilder = MediaMetadata.Builder().apply {
@@ -230,6 +204,89 @@
         whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(false)
     }
 
+    /** Mock view holder for the notification player */
+    private fun initPlayerHolderMocks() {
+        whenever(holder.player).thenReturn(view)
+        whenever(holder.appIcon).thenReturn(appIcon)
+        whenever(holder.albumView).thenReturn(albumView)
+        whenever(holder.titleText).thenReturn(titleText)
+        whenever(holder.artistText).thenReturn(artistText)
+        whenever(seamlessBackground.getDrawable(0)).thenReturn(mock(GradientDrawable::class.java))
+        whenever(holder.seamless).thenReturn(seamless)
+        whenever(holder.seamlessButton).thenReturn(seamlessButton)
+        whenever(holder.seamlessIcon).thenReturn(seamlessIcon)
+        whenever(holder.seamlessText).thenReturn(seamlessText)
+        whenever(holder.seekBar).thenReturn(seekBar)
+        whenever(holder.elapsedTimeView).thenReturn(elapsedTimeView)
+        whenever(holder.totalTimeView).thenReturn(totalTimeView)
+
+        // Action buttons
+        action0 = ImageButton(context)
+        whenever(holder.action0).thenReturn(action0)
+        whenever(holder.getAction(R.id.action0)).thenReturn(action0)
+        action1 = ImageButton(context)
+        whenever(holder.action1).thenReturn(action1)
+        whenever(holder.getAction(R.id.action1)).thenReturn(action1)
+        action2 = ImageButton(context)
+        whenever(holder.action2).thenReturn(action2)
+        whenever(holder.getAction(R.id.action2)).thenReturn(action2)
+        action3 = ImageButton(context)
+        whenever(holder.action3).thenReturn(action3)
+        whenever(holder.getAction(R.id.action3)).thenReturn(action3)
+        action4 = ImageButton(context)
+        whenever(holder.action4).thenReturn(action4)
+        whenever(holder.getAction(R.id.action4)).thenReturn(action4)
+
+        // Long press menu
+        whenever(holder.longPressText).thenReturn(longPressText)
+        whenever(longPressText.handler).thenReturn(handler)
+        whenever(holder.settings).thenReturn(settings)
+        whenever(holder.settingsText).thenReturn(settingsText)
+        whenever(holder.cancel).thenReturn(cancel)
+        whenever(holder.dismiss).thenReturn(dismiss)
+        whenever(holder.dismissLabel).thenReturn(dismissLabel)
+    }
+
+    /** Mock view holder for session player */
+    private fun initSessionHolderMocks() {
+        whenever(sessionHolder.player).thenReturn(view)
+        whenever(sessionHolder.appIcon).thenReturn(appIcon)
+        whenever(sessionHolder.titleText).thenReturn(titleText)
+        whenever(sessionHolder.artistText).thenReturn(artistText)
+        val seamlessBackground = mock(RippleDrawable::class.java)
+        whenever(seamlessBackground.getDrawable(0)).thenReturn(mock(GradientDrawable::class.java))
+        whenever(sessionHolder.seamless).thenReturn(seamless)
+        whenever(sessionHolder.seamlessButton).thenReturn(seamlessButton)
+        whenever(sessionHolder.seamlessIcon).thenReturn(seamlessIcon)
+        whenever(sessionHolder.seamlessText).thenReturn(seamlessText)
+        whenever(sessionHolder.seekBar).thenReturn(seekBar)
+
+        // Action buttons
+        actionPlayPause = ImageButton(context)
+        whenever(sessionHolder.actionPlayPause).thenReturn(actionPlayPause)
+        whenever(sessionHolder.getAction(R.id.actionPlayPause)).thenReturn(actionPlayPause)
+        actionNext = ImageButton(context)
+        whenever(sessionHolder.actionNext).thenReturn(actionNext)
+        whenever(sessionHolder.getAction(R.id.actionNext)).thenReturn(actionNext)
+        actionPrev = ImageButton(context)
+        whenever(sessionHolder.actionPrev).thenReturn(actionPrev)
+        whenever(sessionHolder.getAction(R.id.actionPrev)).thenReturn(actionPrev)
+        actionStart = ImageButton(context)
+        whenever(sessionHolder.actionStart).thenReturn(actionStart)
+        whenever(sessionHolder.getAction(R.id.actionStart)).thenReturn(actionStart)
+        actionEnd = ImageButton(context)
+        whenever(sessionHolder.actionEnd).thenReturn(actionEnd)
+        whenever(sessionHolder.getAction(R.id.actionEnd)).thenReturn(actionEnd)
+
+        // Long press menu
+        whenever(sessionHolder.longPressText).thenReturn(longPressText)
+        whenever(sessionHolder.settings).thenReturn(settings)
+        whenever(sessionHolder.settingsText).thenReturn(settingsText)
+        whenever(sessionHolder.cancel).thenReturn(cancel)
+        whenever(sessionHolder.dismiss).thenReturn(dismiss)
+        whenever(sessionHolder.dismissLabel).thenReturn(dismissLabel)
+    }
+
     @After
     fun tearDown() {
         session.release()
@@ -255,32 +312,28 @@
         )
         val state = mediaData.copy(semanticActions = semanticActions)
 
-        player.attachPlayer(holder)
+        player.attachPlayer(sessionHolder, MediaViewController.TYPE.PLAYER_SESSION)
         player.bindPlayer(state, PACKAGE)
 
-        verify(expandedSet).setVisibility(R.id.action0, ConstraintSet.VISIBLE)
-        assertThat(action0.contentDescription).isEqualTo("custom 1")
-        assertThat(action0.isEnabled()).isFalse()
+        assertThat(actionStart.contentDescription).isEqualTo("custom 1")
+        assertThat(actionStart.isEnabled()).isFalse()
 
-        verify(expandedSet).setVisibility(R.id.action1, ConstraintSet.INVISIBLE)
-        assertThat(action1.isEnabled()).isFalse()
+        assertThat(actionPrev.isEnabled()).isFalse()
+        assertThat(actionPrev.drawable).isNull()
 
-        verify(expandedSet).setVisibility(R.id.action2, ConstraintSet.VISIBLE)
-        assertThat(action2.isEnabled()).isTrue()
-        assertThat(action2.contentDescription).isEqualTo("play")
+        assertThat(actionPlayPause.isEnabled()).isTrue()
+        assertThat(actionPlayPause.contentDescription).isEqualTo("play")
 
-        verify(expandedSet).setVisibility(R.id.action3, ConstraintSet.VISIBLE)
-        assertThat(action3.isEnabled()).isTrue()
-        assertThat(action3.contentDescription).isEqualTo("next")
+        assertThat(actionNext.isEnabled()).isTrue()
+        assertThat(actionNext.contentDescription).isEqualTo("next")
 
-        verify(expandedSet).setVisibility(R.id.action4, ConstraintSet.VISIBLE)
-        assertThat(action4.contentDescription).isEqualTo("custom 2")
-        assertThat(action4.isEnabled()).isFalse()
+        assertThat(actionEnd.contentDescription).isEqualTo("custom 2")
+        assertThat(actionEnd.isEnabled()).isFalse()
     }
 
     @Test
     fun bindText() {
-        player.attachPlayer(holder)
+        player.attachPlayer(holder, MediaViewController.TYPE.PLAYER)
         player.bindPlayer(mediaData, PACKAGE)
         assertThat(titleText.getText()).isEqualTo(TITLE)
         assertThat(artistText.getText()).isEqualTo(ARTIST)
@@ -288,7 +341,7 @@
 
     @Test
     fun bindDevice() {
-        player.attachPlayer(holder)
+        player.attachPlayer(holder, MediaViewController.TYPE.PLAYER)
         player.bindPlayer(mediaData, PACKAGE)
         assertThat(seamlessText.getText()).isEqualTo(DEVICE_NAME)
         assertThat(seamless.contentDescription).isEqualTo(DEVICE_NAME)
@@ -299,7 +352,7 @@
     fun bindDisabledDevice() {
         seamless.id = 1
         val fallbackString = context.getString(R.string.media_seamless_other_device)
-        player.attachPlayer(holder)
+        player.attachPlayer(holder, MediaViewController.TYPE.PLAYER)
         val state = mediaData.copy(device = disabledDevice)
         player.bindPlayer(state, PACKAGE)
         assertThat(seamless.isEnabled()).isFalse()
@@ -310,7 +363,7 @@
     @Test
     fun bindNullDevice() {
         val fallbackString = context.getResources().getString(R.string.media_seamless_other_device)
-        player.attachPlayer(holder)
+        player.attachPlayer(holder, MediaViewController.TYPE.PLAYER)
         val state = mediaData.copy(device = null)
         player.bindPlayer(state, PACKAGE)
         assertThat(seamless.isEnabled()).isTrue()
@@ -320,7 +373,7 @@
 
     @Test
     fun bindDeviceResumptionPlayer() {
-        player.attachPlayer(holder)
+        player.attachPlayer(holder, MediaViewController.TYPE.PLAYER)
         val state = mediaData.copy(resumption = true)
         player.bindPlayer(state, PACKAGE)
         assertThat(seamlessText.getText()).isEqualTo(DEVICE_NAME)
@@ -329,7 +382,7 @@
 
     @Test
     fun longClick_gutsClosed() {
-        player.attachPlayer(holder)
+        player.attachPlayer(holder, MediaViewController.TYPE.PLAYER)
         whenever(mediaViewController.isGutsVisible).thenReturn(false)
 
         val captor = ArgumentCaptor.forClass(View.OnLongClickListener::class.java)
@@ -341,7 +394,7 @@
 
     @Test
     fun longClick_gutsOpen() {
-        player.attachPlayer(holder)
+        player.attachPlayer(holder, MediaViewController.TYPE.PLAYER)
         whenever(mediaViewController.isGutsVisible).thenReturn(true)
 
         val captor = ArgumentCaptor.forClass(View.OnLongClickListener::class.java)
@@ -354,7 +407,7 @@
 
     @Test
     fun cancelButtonClick_animation() {
-        player.attachPlayer(holder)
+        player.attachPlayer(holder, MediaViewController.TYPE.PLAYER)
 
         cancel.callOnClick()
 
@@ -363,7 +416,7 @@
 
     @Test
     fun settingsButtonClick() {
-        player.attachPlayer(holder)
+        player.attachPlayer(holder, MediaViewController.TYPE.PLAYER)
 
         settings.callOnClick()
 
@@ -376,7 +429,7 @@
     @Test
     fun dismissButtonClick() {
         val mediaKey = "key for dismissal"
-        player.attachPlayer(holder)
+        player.attachPlayer(holder, MediaViewController.TYPE.PLAYER)
         val state = mediaData.copy(notificationKey = KEY)
         player.bindPlayer(state, mediaKey)
 
@@ -388,7 +441,7 @@
     @Test
     fun dismissButtonDisabled() {
         val mediaKey = "key for dismissal"
-        player.attachPlayer(holder)
+        player.attachPlayer(holder, MediaViewController.TYPE.PLAYER)
         val state = mediaData.copy(isClearable = false, notificationKey = KEY)
         player.bindPlayer(state, mediaKey)
 
@@ -400,7 +453,7 @@
         val mediaKey = "key for dismissal"
         whenever(mediaDataManager.dismissMediaData(eq(mediaKey), anyLong())).thenReturn(false)
 
-        player.attachPlayer(holder)
+        player.attachPlayer(holder, MediaViewController.TYPE.PLAYER)
         val state = mediaData.copy(notificationKey = KEY)
         player.bindPlayer(state, mediaKey)
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt
index e77802f..3c2392a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt
@@ -62,7 +62,7 @@
         whenever(mockHolder.elapsedTimeView).thenReturn(elapsedTimeView)
         whenever(mockHolder.totalTimeView).thenReturn(totalTimeView)
 
-        observer = SeekBarObserver(mockHolder)
+        observer = SeekBarObserver(mockHolder, false /* useSessionLayout */)
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
index 1b5e5eb..89c0712 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
@@ -100,7 +100,7 @@
     public void getItemCount_zeroMode_containExtraOneForPairNew() {
         when(mMediaOutputController.isZeroMode()).thenReturn(true);
 
-        assertThat(mMediaOutputAdapter.getItemCount()).isEqualTo(mMediaDevices.size() + 1);
+        assertThat(mMediaOutputAdapter.getItemCount()).isEqualTo(mMediaDevices.size());
     }
 
     @Test
@@ -108,7 +108,7 @@
         when(mMediaOutputController.getSelectedMediaDevice()).thenReturn(mMediaDevices);
         when(mMediaOutputController.isZeroMode()).thenReturn(false);
 
-        assertThat(mMediaOutputAdapter.getItemCount()).isEqualTo(mMediaDevices.size() + 1);
+        assertThat(mMediaOutputAdapter.getItemCount()).isEqualTo(mMediaDevices.size());
     }
 
     @Test
@@ -119,7 +119,6 @@
         assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.VISIBLE);
         assertThat(mViewHolder.mTwoLineLayout.getVisibility()).isEqualTo(View.GONE);
         assertThat(mViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE);
-        assertThat(mViewHolder.mAddIcon.getVisibility()).isEqualTo(View.GONE);
         assertThat(mViewHolder.mCheckBox.getVisibility()).isEqualTo(View.GONE);
         assertThat(mViewHolder.mTitleText.getText()).isEqualTo(mContext.getText(
                 R.string.media_output_dialog_pairing_new));
@@ -134,11 +133,10 @@
         mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
 
         assertThat(mViewHolder.mSeekBar.getVisibility()).isEqualTo(View.VISIBLE);
-        assertThat(mViewHolder.mTwoLineLayout.getVisibility()).isEqualTo(View.VISIBLE);
-        assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.GONE);
+        assertThat(mViewHolder.mTwoLineLayout.getVisibility()).isEqualTo(View.GONE);
+        assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.VISIBLE);
         assertThat(mViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE);
-        assertThat(mViewHolder.mCheckBox.getVisibility()).isEqualTo(View.GONE);
-        assertThat(mViewHolder.mTwoLineTitleText.getText()).isEqualTo(TEST_SESSION_NAME);
+        assertThat(mViewHolder.mCheckBox.getVisibility()).isEqualTo(View.VISIBLE);
     }
 
     @Test
@@ -150,12 +148,10 @@
         mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
 
         assertThat(mViewHolder.mSeekBar.getVisibility()).isEqualTo(View.VISIBLE);
-        assertThat(mViewHolder.mTwoLineLayout.getVisibility()).isEqualTo(View.VISIBLE);
-        assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.GONE);
+        assertThat(mViewHolder.mTwoLineLayout.getVisibility()).isEqualTo(View.GONE);
+        assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.VISIBLE);
         assertThat(mViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE);
-        assertThat(mViewHolder.mCheckBox.getVisibility()).isEqualTo(View.GONE);
-        assertThat(mViewHolder.mTwoLineTitleText.getText()).isEqualTo(mContext.getString(
-                R.string.media_output_dialog_group));
+        assertThat(mViewHolder.mCheckBox.getVisibility()).isEqualTo(View.VISIBLE);
     }
 
     @Test
@@ -172,26 +168,9 @@
     }
 
     @Test
-    public void onBindViewHolder_bindConnectedDevice_withSelectableDevice_showAddIcon() {
-        when(mMediaOutputController.getSelectableMediaDevice()).thenReturn(mMediaDevices);
-        mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
-
-        assertThat(mViewHolder.mAddIcon.getVisibility()).isEqualTo(View.VISIBLE);
-    }
-
-    @Test
-    public void onBindViewHolder_bindConnectedDevice_withoutSelectableDevice_hideAddIcon() {
-        when(mMediaOutputController.getSelectableMediaDevice()).thenReturn(new ArrayList<>());
-        mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
-
-        assertThat(mViewHolder.mAddIcon.getVisibility()).isEqualTo(View.GONE);
-    }
-
-    @Test
     public void onBindViewHolder_bindNonActiveConnectedDevice_verifyView() {
         mMediaOutputAdapter.onBindViewHolder(mViewHolder, 1);
 
-        assertThat(mViewHolder.mAddIcon.getVisibility()).isEqualTo(View.GONE);
         assertThat(mViewHolder.mTwoLineLayout.getVisibility()).isEqualTo(View.GONE);
         assertThat(mViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE);
         assertThat(mViewHolder.mCheckBox.getVisibility()).isEqualTo(View.GONE);
@@ -206,7 +185,6 @@
         when(mMediaDevice2.isConnected()).thenReturn(false);
         mMediaOutputAdapter.onBindViewHolder(mViewHolder, 1);
 
-        assertThat(mViewHolder.mAddIcon.getVisibility()).isEqualTo(View.GONE);
         assertThat(mViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE);
         assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.VISIBLE);
         assertThat(mViewHolder.mTitleText.getText().toString()).isEqualTo(
@@ -220,7 +198,6 @@
                 LocalMediaManager.MediaDeviceState.STATE_CONNECTING_FAILED);
         mMediaOutputAdapter.onBindViewHolder(mViewHolder, 1);
 
-        assertThat(mViewHolder.mAddIcon.getVisibility()).isEqualTo(View.GONE);
         assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.GONE);
         assertThat(mViewHolder.mSeekBar.getVisibility()).isEqualTo(View.GONE);
         assertThat(mViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputGroupAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputGroupAdapterTest.java
index 2c883a7..cf6fd24 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputGroupAdapterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputGroupAdapterTest.java
@@ -99,7 +99,6 @@
         assertThat(mGroupViewHolder.mCheckBox.getVisibility()).isEqualTo(View.GONE);
         assertThat(mGroupViewHolder.mSubTitleText.getVisibility()).isEqualTo(View.GONE);
         assertThat(mGroupViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE);
-        assertThat(mGroupViewHolder.mAddIcon.getVisibility()).isEqualTo(View.GONE);
         assertThat(mGroupViewHolder.mSeekBar.getVisibility()).isEqualTo(View.VISIBLE);
         assertThat(mGroupViewHolder.mTwoLineTitleText.getVisibility()).isEqualTo(View.VISIBLE);
         assertThat(mGroupViewHolder.mTwoLineTitleText.getText()).isEqualTo(mContext.getText(
@@ -112,7 +111,6 @@
 
         assertThat(mGroupViewHolder.mTitleText.getVisibility()).isEqualTo(View.GONE);
         assertThat(mGroupViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE);
-        assertThat(mGroupViewHolder.mAddIcon.getVisibility()).isEqualTo(View.GONE);
         assertThat(mGroupViewHolder.mSubTitleText.getVisibility()).isEqualTo(View.GONE);
         assertThat(mGroupViewHolder.mSeekBar.getVisibility()).isEqualTo(View.VISIBLE);
         assertThat(mGroupViewHolder.mTwoLineTitleText.getVisibility()).isEqualTo(View.VISIBLE);
@@ -137,7 +135,6 @@
 
         assertThat(mGroupViewHolder.mTitleText.getVisibility()).isEqualTo(View.GONE);
         assertThat(mGroupViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE);
-        assertThat(mGroupViewHolder.mAddIcon.getVisibility()).isEqualTo(View.GONE);
         assertThat(mGroupViewHolder.mSubTitleText.getVisibility()).isEqualTo(View.GONE);
         assertThat(mGroupViewHolder.mSeekBar.getVisibility()).isEqualTo(View.VISIBLE);
         assertThat(mGroupViewHolder.mTwoLineTitleText.getVisibility()).isEqualTo(View.VISIBLE);
@@ -161,7 +158,6 @@
 
         assertThat(mGroupViewHolder.mTitleText.getVisibility()).isEqualTo(View.GONE);
         assertThat(mGroupViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE);
-        assertThat(mGroupViewHolder.mAddIcon.getVisibility()).isEqualTo(View.GONE);
         assertThat(mGroupViewHolder.mSubTitleText.getVisibility()).isEqualTo(View.GONE);
         assertThat(mGroupViewHolder.mSeekBar.getVisibility()).isEqualTo(View.VISIBLE);
         assertThat(mGroupViewHolder.mTwoLineTitleText.getVisibility()).isEqualTo(View.VISIBLE);
@@ -178,7 +174,6 @@
 
         assertThat(mGroupViewHolder.mTitleText.getVisibility()).isEqualTo(View.GONE);
         assertThat(mGroupViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE);
-        assertThat(mGroupViewHolder.mAddIcon.getVisibility()).isEqualTo(View.GONE);
         assertThat(mGroupViewHolder.mSubTitleText.getVisibility()).isEqualTo(View.GONE);
         assertThat(mGroupViewHolder.mSeekBar.getVisibility()).isEqualTo(View.VISIBLE);
         assertThat(mGroupViewHolder.mTwoLineTitleText.getVisibility()).isEqualTo(View.VISIBLE);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt
index 9b2d3eb..dec5a10 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt
@@ -18,6 +18,12 @@
 
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.media.taptotransfer.receiver.ChipStateReceiver
+import com.android.systemui.media.taptotransfer.receiver.MediaTttChipControllerReceiver
+import com.android.systemui.media.taptotransfer.sender.MediaTttChipControllerSender
+import com.android.systemui.media.taptotransfer.sender.MoveCloserToTransfer
+import com.android.systemui.media.taptotransfer.sender.TransferInitiated
+import com.android.systemui.media.taptotransfer.sender.TransferSucceeded
 import com.android.systemui.statusbar.commandline.Command
 import com.android.systemui.statusbar.commandline.CommandRegistry
 import com.android.systemui.util.concurrency.FakeExecutor
@@ -42,80 +48,118 @@
     private lateinit var mediaTttCommandLineHelper: MediaTttCommandLineHelper
 
     @Mock
-    private lateinit var mediaTttChipController: MediaTttChipController
+    private lateinit var mediaTttChipControllerSender: MediaTttChipControllerSender
+    @Mock
+    private lateinit var mediaTttChipControllerReceiver: MediaTttChipControllerReceiver
 
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
         mediaTttCommandLineHelper =
             MediaTttCommandLineHelper(
-                commandRegistry, mediaTttChipController, FakeExecutor(FakeSystemClock())
+                commandRegistry,
+                context,
+                mediaTttChipControllerSender,
+                mediaTttChipControllerReceiver,
+                FakeExecutor(FakeSystemClock())
             )
     }
 
     @Test(expected = IllegalStateException::class)
-    fun constructor_addCommandAlreadyRegistered() {
+    fun constructor_addSenderCommandAlreadyRegistered() {
         // Since creating the chip controller should automatically register the add command, it
         // should throw when registering it again.
         commandRegistry.registerCommand(
-            ADD_CHIP_COMMAND_TAG
+            ADD_CHIP_COMMAND_SENDER_TAG
         ) { EmptyCommand() }
     }
 
     @Test(expected = IllegalStateException::class)
-    fun constructor_removeCommandAlreadyRegistered() {
+    fun constructor_removeSenderCommandAlreadyRegistered() {
         // Since creating the chip controller should automatically register the remove command, it
         // should throw when registering it again.
         commandRegistry.registerCommand(
-            REMOVE_CHIP_COMMAND_TAG
+            REMOVE_CHIP_COMMAND_SENDER_TAG
+        ) { EmptyCommand() }
+    }
+
+    @Test(expected = IllegalStateException::class)
+    fun constructor_addReceiverCommandAlreadyRegistered() {
+        // Since creating the chip controller should automatically register the add command, it
+        // should throw when registering it again.
+        commandRegistry.registerCommand(
+            ADD_CHIP_COMMAND_RECEIVER_TAG
+        ) { EmptyCommand() }
+    }
+
+    @Test(expected = IllegalStateException::class)
+    fun constructor_removeReceiverCommandAlreadyRegistered() {
+        // Since creating the chip controller should automatically register the remove command, it
+        // should throw when registering it again.
+        commandRegistry.registerCommand(
+            REMOVE_CHIP_COMMAND_RECEIVER_TAG
         ) { EmptyCommand() }
     }
 
     @Test
-    fun moveCloserToTransfer_chipDisplayWithCorrectState() {
+    fun sender_moveCloserToTransfer_chipDisplayWithCorrectState() {
         commandRegistry.onShellCommand(pw, getMoveCloserToTransferCommand())
 
-        verify(mediaTttChipController).displayChip(any(MoveCloserToTransfer::class.java))
+        verify(mediaTttChipControllerSender).displayChip(any(MoveCloserToTransfer::class.java))
     }
 
     @Test
-    fun transferInitiated_chipDisplayWithCorrectState() {
+    fun sender_transferInitiated_chipDisplayWithCorrectState() {
         commandRegistry.onShellCommand(pw, getTransferInitiatedCommand())
 
-        verify(mediaTttChipController).displayChip(any(TransferInitiated::class.java))
+        verify(mediaTttChipControllerSender).displayChip(any(TransferInitiated::class.java))
     }
 
     @Test
-    fun transferSucceeded_chipDisplayWithCorrectState() {
+    fun sender_transferSucceeded_chipDisplayWithCorrectState() {
         commandRegistry.onShellCommand(pw, getTransferSucceededCommand())
 
-        verify(mediaTttChipController).displayChip(any(TransferSucceeded::class.java))
+        verify(mediaTttChipControllerSender).displayChip(any(TransferSucceeded::class.java))
     }
 
     @Test
-    fun removeCommand_chipRemoved() {
-        commandRegistry.onShellCommand(pw, arrayOf(REMOVE_CHIP_COMMAND_TAG))
+    fun sender_removeCommand_chipRemoved() {
+        commandRegistry.onShellCommand(pw, arrayOf(REMOVE_CHIP_COMMAND_SENDER_TAG))
 
-        verify(mediaTttChipController).removeChip()
+        verify(mediaTttChipControllerSender).removeChip()
+    }
+
+    @Test
+    fun receiver_addCommand_chipAdded() {
+        commandRegistry.onShellCommand(pw, arrayOf(ADD_CHIP_COMMAND_RECEIVER_TAG))
+
+        verify(mediaTttChipControllerReceiver).displayChip(any(ChipStateReceiver::class.java))
+    }
+
+    @Test
+    fun receiver_removeCommand_chipRemoved() {
+        commandRegistry.onShellCommand(pw, arrayOf(REMOVE_CHIP_COMMAND_RECEIVER_TAG))
+
+        verify(mediaTttChipControllerReceiver).removeChip()
     }
 
     private fun getMoveCloserToTransferCommand(): Array<String> =
         arrayOf(
-            ADD_CHIP_COMMAND_TAG,
+            ADD_CHIP_COMMAND_SENDER_TAG,
             DEVICE_NAME,
             MOVE_CLOSER_TO_TRANSFER_COMMAND_NAME
         )
 
     private fun getTransferInitiatedCommand(): Array<String> =
         arrayOf(
-            ADD_CHIP_COMMAND_TAG,
+            ADD_CHIP_COMMAND_SENDER_TAG,
             DEVICE_NAME,
             TRANSFER_INITIATED_COMMAND_NAME
         )
 
     private fun getTransferSucceededCommand(): Array<String> =
         arrayOf(
-            ADD_CHIP_COMMAND_TAG,
+            ADD_CHIP_COMMAND_SENDER_TAG,
             DEVICE_NAME,
             TRANSFER_SUCCEEDED_COMMAND_NAME
         )
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt
new file mode 100644
index 0000000..927ca7a
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.media.taptotransfer.common
+
+import android.content.Context
+import android.graphics.drawable.Drawable
+import android.graphics.drawable.Icon
+import android.view.View
+import android.view.ViewGroup
+import android.view.WindowManager
+import android.widget.ImageView
+import androidx.test.filters.SmallTest
+import com.android.systemui.R
+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.Test
+import org.mockito.ArgumentCaptor
+import org.mockito.Mock
+import org.mockito.Mockito.never
+import org.mockito.Mockito.reset
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+class MediaTttChipControllerCommonTest : SysuiTestCase() {
+    private lateinit var controllerCommon: MediaTttChipControllerCommon<MediaTttChipState>
+
+    private lateinit var appIconDrawable: Drawable
+    @Mock
+    private lateinit var windowManager: WindowManager
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+        appIconDrawable = Icon.createWithResource(context, R.drawable.ic_cake).loadDrawable(context)
+        controllerCommon = TestControllerCommon(context, windowManager)
+    }
+
+    @Test
+    fun displayChip_chipAdded() {
+        controllerCommon.displayChip(getState())
+
+        verify(windowManager).addView(any(), any())
+    }
+
+    @Test
+    fun displayChip_twice_chipNotAddedTwice() {
+        controllerCommon.displayChip(getState())
+        reset(windowManager)
+
+        controllerCommon.displayChip(getState())
+        verify(windowManager, never()).addView(any(), any())
+    }
+
+    @Test
+    fun removeChip_chipRemoved() {
+        // First, add the chip
+        controllerCommon.displayChip(getState())
+
+        // Then, remove it
+        controllerCommon.removeChip()
+
+        verify(windowManager).removeView(any())
+    }
+
+    @Test
+    fun removeChip_noAdd_viewNotRemoved() {
+        controllerCommon.removeChip()
+
+        verify(windowManager, never()).removeView(any())
+    }
+
+    @Test
+    fun setIcon_viewHasIconAndContentDescription() {
+        controllerCommon.displayChip(getState())
+        val chipView = getChipView()
+        val drawable = Icon.createWithResource(context, R.drawable.ic_cake).loadDrawable(context)
+        val contentDescription = "test description"
+
+        controllerCommon.setIcon(MediaTttChipState(drawable, contentDescription), chipView)
+
+        assertThat(chipView.getAppIconView().drawable).isEqualTo(drawable)
+        assertThat(chipView.getAppIconView().contentDescription).isEqualTo(contentDescription)
+    }
+
+    private fun getState() = MediaTttChipState(appIconDrawable, APP_ICON_CONTENT_DESCRIPTION)
+
+    private fun getChipView(): ViewGroup {
+        val viewCaptor = ArgumentCaptor.forClass(View::class.java)
+        verify(windowManager).addView(viewCaptor.capture(), any())
+        return viewCaptor.value as ViewGroup
+    }
+
+    private fun ViewGroup.getAppIconView() = this.requireViewById<ImageView>(R.id.app_icon)
+
+    inner class TestControllerCommon(
+        context: Context,
+        windowManager: WindowManager
+    ) : MediaTttChipControllerCommon<MediaTttChipState>(
+        context, windowManager, R.layout.media_ttt_chip
+    ) {
+        override fun updateChipView(chipState: MediaTttChipState, currentChipView: ViewGroup) {
+        }
+    }
+}
+
+private const val APP_ICON_CONTENT_DESCRIPTION = "Content description"
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt
new file mode 100644
index 0000000..afaab80
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.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.media.taptotransfer.receiver
+
+import android.graphics.drawable.Icon
+import android.view.View
+import android.view.ViewGroup
+import android.view.WindowManager
+import android.widget.ImageView
+import androidx.test.filters.SmallTest
+import com.android.systemui.R
+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.Test
+import org.mockito.ArgumentCaptor
+import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+class MediaTttChipControllerReceiverTest : SysuiTestCase() {
+    private lateinit var controllerReceiver: MediaTttChipControllerReceiver
+
+    @Mock
+    private lateinit var windowManager: WindowManager
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+        controllerReceiver = MediaTttChipControllerReceiver(context, windowManager)
+    }
+
+    @Test
+    fun displayChip_chipContainsIcon() {
+        val drawable = Icon.createWithResource(context, R.drawable.ic_cake).loadDrawable(context)
+        val contentDescription = "Test description"
+
+        controllerReceiver.displayChip(ChipStateReceiver(drawable, contentDescription))
+
+        assertThat(getChipView().getAppIconView().drawable).isEqualTo(drawable)
+        assertThat(getChipView().getAppIconView().contentDescription).isEqualTo(contentDescription)
+    }
+
+    private fun getChipView(): ViewGroup {
+        val viewCaptor = ArgumentCaptor.forClass(View::class.java)
+        Mockito.verify(windowManager).addView(viewCaptor.capture(), any())
+        return viewCaptor.value as ViewGroup
+    }
+
+    private fun ViewGroup.getAppIconView() = this.requireViewById<ImageView>(R.id.app_icon)
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttChipControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt
similarity index 67%
rename from packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttChipControllerTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt
index 8749917..caef5b9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttChipControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt
@@ -14,10 +14,13 @@
  * limitations under the License.
  */
 
-package com.android.systemui.media.taptotransfer
+package com.android.systemui.media.taptotransfer.sender
 
+import android.graphics.drawable.Drawable
+import android.graphics.drawable.Icon
 import android.view.View
 import android.view.WindowManager
+import android.widget.ImageView
 import android.widget.LinearLayout
 import android.widget.TextView
 import androidx.test.filters.SmallTest
@@ -32,20 +35,19 @@
 import org.junit.Test
 import org.mockito.ArgumentCaptor
 import org.mockito.Mock
-import org.mockito.Mockito.never
-import org.mockito.Mockito.reset
 import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
+import java.util.concurrent.Future
 
 @SmallTest
-class MediaTttChipControllerTest : SysuiTestCase() {
-
+class MediaTttChipControllerSenderTest : SysuiTestCase() {
+    private lateinit var appIconDrawable: Drawable
     private lateinit var fakeMainClock: FakeSystemClock
     private lateinit var fakeMainExecutor: FakeExecutor
     private lateinit var fakeBackgroundClock: FakeSystemClock
     private lateinit var fakeBackgroundExecutor: FakeExecutor
 
-    private lateinit var mediaTttChipController: MediaTttChipController
+    private lateinit var controllerSender: MediaTttChipControllerSender
 
     @Mock
     private lateinit var windowManager: WindowManager
@@ -53,68 +55,39 @@
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
+        appIconDrawable = Icon.createWithResource(context, R.drawable.ic_cake).loadDrawable(context)
         fakeMainClock = FakeSystemClock()
         fakeMainExecutor = FakeExecutor(fakeMainClock)
         fakeBackgroundClock = FakeSystemClock()
         fakeBackgroundExecutor = FakeExecutor(fakeBackgroundClock)
-        mediaTttChipController = MediaTttChipController(
+        controllerSender = MediaTttChipControllerSender(
             context, windowManager, fakeMainExecutor, fakeBackgroundExecutor
         )
     }
 
     @Test
-    fun displayChip_chipAdded() {
-        mediaTttChipController.displayChip(MoveCloserToTransfer(DEVICE_NAME))
-
-        verify(windowManager).addView(any(), any())
-    }
-
-    @Test
-    fun displayChip_twice_chipNotAddedTwice() {
-        mediaTttChipController.displayChip(MoveCloserToTransfer(DEVICE_NAME))
-        reset(windowManager)
-
-        mediaTttChipController.displayChip(MoveCloserToTransfer(DEVICE_NAME))
-        verify(windowManager, never()).addView(any(), any())
-    }
-
-    @Test
-    fun removeChip_chipRemoved() {
-        // First, add the chip
-        mediaTttChipController.displayChip(MoveCloserToTransfer(DEVICE_NAME))
-
-        // Then, remove it
-        mediaTttChipController.removeChip()
-
-        verify(windowManager).removeView(any())
-    }
-
-    @Test
-    fun removeChip_noAdd_viewNotRemoved() {
-        mediaTttChipController.removeChip()
-
-        verify(windowManager, never()).removeView(any())
-    }
-
-    @Test
-    fun moveCloserToTransfer_chipTextContainsDeviceName_noLoadingIcon_noUndo() {
-        mediaTttChipController.displayChip(MoveCloserToTransfer(DEVICE_NAME))
+    fun moveCloserToTransfer_appIcon_chipTextContainsDeviceName_noLoadingIcon_noUndo() {
+        controllerSender.displayChip(moveCloserToTransfer())
 
         val chipView = getChipView()
+        assertThat(chipView.getAppIconView().drawable).isEqualTo(appIconDrawable)
+        assertThat(chipView.getAppIconView().contentDescription).isEqualTo(APP_ICON_CONTENT_DESC)
         assertThat(chipView.getChipText()).contains(DEVICE_NAME)
         assertThat(chipView.getLoadingIconVisibility()).isEqualTo(View.GONE)
         assertThat(chipView.getUndoButton().visibility).isEqualTo(View.GONE)
     }
 
     @Test
-    fun transferInitiated_futureNotResolvedYet_loadingIcon_noUndo() {
+    fun transferInitiated_futureNotResolvedYet_appIcon_loadingIcon_noUndo() {
         val future: SettableFuture<Runnable?> = SettableFuture.create()
-        mediaTttChipController.displayChip(TransferInitiated(DEVICE_NAME, future))
+        controllerSender.displayChip(transferInitiated(future))
 
         // Don't resolve the future in any way and don't run our executors
 
         // Assert we're still in the loading state
         val chipView = getChipView()
+        assertThat(chipView.getAppIconView().drawable).isEqualTo(appIconDrawable)
+        assertThat(chipView.getAppIconView().contentDescription).isEqualTo(APP_ICON_CONTENT_DESC)
         assertThat(chipView.getChipText()).contains(DEVICE_NAME)
         assertThat(chipView.getLoadingIconVisibility()).isEqualTo(View.VISIBLE)
         assertThat(chipView.getUndoButton().visibility).isEqualTo(View.GONE)
@@ -125,7 +98,7 @@
         val future: SettableFuture<Runnable?> = SettableFuture.create()
         val undoRunnable = Runnable { }
 
-        mediaTttChipController.displayChip(TransferInitiated(DEVICE_NAME, future))
+        controllerSender.displayChip(transferInitiated(future))
 
         future.set(undoRunnable)
         fakeBackgroundExecutor.advanceClockToLast()
@@ -146,7 +119,7 @@
     fun transferInitiated_futureCancelled_chipRemoved() {
         val future: SettableFuture<Runnable?> = SettableFuture.create()
 
-        mediaTttChipController.displayChip(TransferInitiated(DEVICE_NAME, future))
+        controllerSender.displayChip(transferInitiated(future))
 
         future.cancel(true)
         fakeBackgroundExecutor.advanceClockToLast()
@@ -163,7 +136,7 @@
     @Test
     fun transferInitiated_futureNotResolvedAfterTimeout_chipRemoved() {
         val future: SettableFuture<Runnable?> = SettableFuture.create()
-        mediaTttChipController.displayChip(TransferInitiated(DEVICE_NAME, future))
+        controllerSender.displayChip(transferInitiated(future))
 
         // We won't set anything on the future, but we will still run the executors so that we're
         // waiting on the future resolving. If we have a bug in our code, then this test will time
@@ -180,22 +153,29 @@
     }
 
     @Test
-    fun transferSucceededNullUndoRunnable_chipTextContainsDeviceName_noLoadingIcon_noUndo() {
-        mediaTttChipController.displayChip(TransferSucceeded(DEVICE_NAME, undoRunnable = null))
+    fun transferSucceeded_appIcon_chipTextContainsDeviceName_noLoadingIcon() {
+        controllerSender.displayChip(transferSucceeded())
 
         val chipView = getChipView()
+        assertThat(chipView.getAppIconView().drawable).isEqualTo(appIconDrawable)
+        assertThat(chipView.getAppIconView().contentDescription).isEqualTo(APP_ICON_CONTENT_DESC)
         assertThat(chipView.getChipText()).contains(DEVICE_NAME)
         assertThat(chipView.getLoadingIconVisibility()).isEqualTo(View.GONE)
+    }
+
+    @Test
+    fun transferSucceededNullUndoRunnable_noUndo() {
+        controllerSender.displayChip(transferSucceeded(undoRunnable = null))
+
+        val chipView = getChipView()
         assertThat(chipView.getUndoButton().visibility).isEqualTo(View.GONE)
     }
 
     @Test
-    fun transferSucceededWithUndoRunnable_chipTextContainsDeviceName_noLoadingIcon_undoWithClick() {
-        mediaTttChipController.displayChip(TransferSucceeded(DEVICE_NAME) { })
+    fun transferSucceededWithUndoRunnable_undoWithClick() {
+        controllerSender.displayChip(transferSucceeded { })
 
         val chipView = getChipView()
-        assertThat(chipView.getChipText()).contains(DEVICE_NAME)
-        assertThat(chipView.getLoadingIconVisibility()).isEqualTo(View.GONE)
         assertThat(chipView.getUndoButton().visibility).isEqualTo(View.VISIBLE)
         assertThat(chipView.getUndoButton().hasOnClickListeners()).isTrue()
     }
@@ -205,7 +185,7 @@
         var runnableRun = false
         val runnable = Runnable { runnableRun = true }
 
-        mediaTttChipController.displayChip(TransferSucceeded(DEVICE_NAME, runnable))
+        controllerSender.displayChip(transferSucceeded(undoRunnable = runnable))
         getChipView().getUndoButton().performClick()
 
         assertThat(runnableRun).isTrue()
@@ -213,36 +193,38 @@
 
     @Test
     fun changeFromCloserToTransferToTransferInitiated_loadingIconAppears() {
-        mediaTttChipController.displayChip(MoveCloserToTransfer(DEVICE_NAME))
-        mediaTttChipController.displayChip(TransferInitiated(DEVICE_NAME, TEST_FUTURE))
+        controllerSender.displayChip(moveCloserToTransfer())
+        controllerSender.displayChip(transferInitiated())
 
         assertThat(getChipView().getLoadingIconVisibility()).isEqualTo(View.VISIBLE)
     }
 
     @Test
     fun changeFromTransferInitiatedToTransferSucceeded_loadingIconDisappears() {
-        mediaTttChipController.displayChip(TransferInitiated(DEVICE_NAME, TEST_FUTURE))
-        mediaTttChipController.displayChip(TransferSucceeded(DEVICE_NAME))
+        controllerSender.displayChip(transferInitiated())
+        controllerSender.displayChip(transferSucceeded())
 
         assertThat(getChipView().getLoadingIconVisibility()).isEqualTo(View.GONE)
     }
 
     @Test
     fun changeFromTransferInitiatedToTransferSucceeded_undoButtonAppears() {
-        mediaTttChipController.displayChip(TransferInitiated(DEVICE_NAME, TEST_FUTURE))
-        mediaTttChipController.displayChip(TransferSucceeded(DEVICE_NAME) { })
+        controllerSender.displayChip(transferInitiated())
+        controllerSender.displayChip(transferSucceeded { })
 
         assertThat(getChipView().getUndoButton().visibility).isEqualTo(View.VISIBLE)
     }
 
     @Test
     fun changeFromTransferSucceededToMoveCloser_undoButtonDisappears() {
-        mediaTttChipController.displayChip(TransferSucceeded(DEVICE_NAME))
-        mediaTttChipController.displayChip(MoveCloserToTransfer(DEVICE_NAME))
+        controllerSender.displayChip(transferSucceeded())
+        controllerSender.displayChip(moveCloserToTransfer())
 
         assertThat(getChipView().getUndoButton().visibility).isEqualTo(View.GONE)
     }
 
+    private fun LinearLayout.getAppIconView() = this.requireViewById<ImageView>(R.id.app_icon)
+
     private fun LinearLayout.getChipText(): String =
         (this.requireViewById<TextView>(R.id.text)).text as String
 
@@ -256,9 +238,24 @@
         verify(windowManager).addView(viewCaptor.capture(), any())
         return viewCaptor.value as LinearLayout
     }
+
+    /** Helper method providing default parameters to not clutter up the tests. */
+    private fun moveCloserToTransfer() =
+        MoveCloserToTransfer(appIconDrawable, APP_ICON_CONTENT_DESC, DEVICE_NAME)
+
+    /** Helper method providing default parameters to not clutter up the tests. */
+    private fun transferInitiated(
+        future: Future<Runnable?> = TEST_FUTURE
+    ) = TransferInitiated(appIconDrawable, APP_ICON_CONTENT_DESC, DEVICE_NAME, future)
+
+    /** Helper method providing default parameters to not clutter up the tests. */
+    private fun transferSucceeded(
+        undoRunnable: Runnable? = null
+    ) = TransferSucceeded(appIconDrawable, APP_ICON_CONTENT_DESC, DEVICE_NAME, undoRunnable)
 }
 
 private const val DEVICE_NAME = "My Tablet"
+private const val APP_ICON_CONTENT_DESC = "Content description"
 // Use a settable future that hasn't yet been set so that we don't immediately switch to the success
 // state.
 private val TEST_FUTURE: SettableFuture<Runnable?> = SettableFuture.create()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSFactoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSFactoryImplTest.kt
index af33daf..968b12a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSFactoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSFactoryImplTest.kt
@@ -29,6 +29,7 @@
 import com.android.systemui.qs.tiles.CameraToggleTile
 import com.android.systemui.qs.tiles.CastTile
 import com.android.systemui.qs.tiles.CellularTile
+import com.android.systemui.qs.tiles.ColorCorrectionTile
 import com.android.systemui.qs.tiles.ColorInversionTile
 import com.android.systemui.qs.tiles.DataSaverTile
 import com.android.systemui.qs.tiles.DeviceControlsTile
@@ -91,7 +92,8 @@
         "wallet" to QuickAccessWalletTile::class.java,
         "qr_code_scanner" to QRCodeScannerTile::class.java,
         "onehanded" to OneHandedModeTile::class.java,
-        "fgsmanager" to FgsManagerTile::class.java
+        "fgsmanager" to FgsManagerTile::class.java,
+        "color_correction" to ColorCorrectionTile::class.java
 )
 
 @RunWith(AndroidTestingRunner::class)
@@ -132,6 +134,7 @@
     @Mock private lateinit var qrCodeScannerTile: QRCodeScannerTile
     @Mock private lateinit var oneHandedModeTile: OneHandedModeTile
     @Mock private lateinit var fgsManagerTile: FgsManagerTile
+    @Mock private lateinit var colorCorrectionTile: ColorCorrectionTile
 
     private lateinit var factory: QSFactoryImpl
 
@@ -175,7 +178,8 @@
                 { quickAccessWalletTile },
                 { qrCodeScannerTile },
                 { oneHandedModeTile },
-                { fgsManagerTile }
+                { fgsManagerTile },
+                { colorCorrectionTile }
         )
         // When adding/removing tiles, fix also [specMap]
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ColorCorrectionTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ColorCorrectionTileTest.java
new file mode 100644
index 0000000..debe41c
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ColorCorrectionTileTest.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.tiles;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Intent;
+import android.os.Handler;
+import android.provider.Settings;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.UiEventLogger;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.classifier.FalsingManagerFake;
+import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.qs.logging.QSLogger;
+import com.android.systemui.settings.UserTracker;
+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.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@SmallTest
+public class ColorCorrectionTileTest extends SysuiTestCase {
+
+    @Mock
+    private QSTileHost mHost;
+    @Mock
+    private MetricsLogger mMetricsLogger;
+    @Mock
+    private StatusBarStateController mStatusBarStateController;
+    @Mock
+    private ActivityStarter mActivityStarter;
+    @Mock
+    private QSLogger mQSLogger;
+    @Mock
+    private UiEventLogger mUiEventLogger;
+    @Mock
+    private UserTracker mUserTracker;
+
+    private TestableLooper mTestableLooper;
+    private SecureSettings mSecureSettings;
+    private ColorCorrectionTile mTile;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+
+        mSecureSettings = new FakeSettings();
+        mTestableLooper = TestableLooper.get(this);
+
+        when(mHost.getContext()).thenReturn(mContext);
+        when(mHost.getUiEventLogger()).thenReturn(mUiEventLogger);
+
+        mTile = new ColorCorrectionTile(
+                mHost,
+                mTestableLooper.getLooper(),
+                new Handler(mTestableLooper.getLooper()),
+                new FalsingManagerFake(),
+                mMetricsLogger,
+                mStatusBarStateController,
+                mActivityStarter,
+                mQSLogger,
+                mUserTracker,
+                mSecureSettings
+        );
+
+        mTile.initialize();
+        mTestableLooper.processAllMessages();
+    }
+
+    @Test
+    public void longClick_expectedAction() {
+        final ArgumentCaptor<Intent> IntentCaptor = ArgumentCaptor.forClass(Intent.class);
+
+        mTile.longClick(/* view= */ null);
+        mTestableLooper.processAllMessages();
+
+        verify(mActivityStarter).postStartActivityDismissingKeyguard(IntentCaptor.capture(),
+                anyInt(), any());
+        assertThat(IntentCaptor.getValue().getAction()).isEqualTo(
+                Settings.ACTION_COLOR_CORRECTION_SETTINGS);
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RotationLockTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RotationLockTileTest.java
new file mode 100644
index 0000000..55c51b2
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RotationLockTileTest.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.tiles;
+
+import static android.hardware.SensorPrivacyManager.Sensors.CAMERA;
+
+import static junit.framework.TestCase.assertEquals;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.when;
+
+import android.Manifest;
+import android.content.pm.PackageManager;
+import android.hardware.SensorPrivacyManager;
+import android.os.Handler;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.classifier.FalsingManagerFake;
+import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.qs.logging.QSLogger;
+import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.DeviceStateRotationLockSettingController;
+import com.android.systemui.statusbar.policy.RotationLockController;
+import com.android.systemui.statusbar.policy.RotationLockControllerImpl;
+import com.android.systemui.util.settings.FakeSettings;
+import com.android.systemui.util.wrapper.RotationPolicyWrapper;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@SmallTest
+public class RotationLockTileTest extends SysuiTestCase {
+
+    private static final String PACKAGE_NAME = "package_name";
+    private static final String[] DEFAULT_SETTINGS = new String[]{
+            "0:0",
+            "1:2"
+    };
+
+    @Mock
+    private PackageManager mPackageManager;
+    @Mock
+    private ActivityStarter mActivityStarter;
+    @Mock
+    private QSTileHost mHost;
+    @Mock
+    private MetricsLogger mMetricsLogger;
+    @Mock
+    private StatusBarStateController mStatusBarStateController;
+    @Mock
+    private QSLogger mQSLogger;
+    @Mock
+    private SensorPrivacyManager mPrivacyManager;
+    @Mock
+    private BatteryController mBatteryController;
+    @Mock
+    DeviceStateRotationLockSettingController mDeviceStateRotationLockSettingController;
+    @Mock
+    RotationPolicyWrapper mRotationPolicyWrapper;
+
+    private RotationLockController mController;
+    private TestableLooper mTestableLooper;
+    private RotationLockTile mLockTile;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        mTestableLooper = TestableLooper.get(this);
+
+        when(mHost.getContext()).thenReturn(mContext);
+        when(mHost.getUserContext()).thenReturn(mContext);
+
+        mController = new RotationLockControllerImpl(mRotationPolicyWrapper,
+                mDeviceStateRotationLockSettingController, DEFAULT_SETTINGS);
+
+        mLockTile = new RotationLockTile(
+                mHost,
+                mTestableLooper.getLooper(),
+                new Handler(mTestableLooper.getLooper()),
+                new FalsingManagerFake(),
+                mMetricsLogger,
+                mStatusBarStateController,
+                mActivityStarter,
+                mQSLogger,
+                mController,
+                mPrivacyManager,
+                mBatteryController,
+                new FakeSettings()
+        );
+
+        mLockTile.initialize();
+
+        // We are not setting the mocks to listening, so we trigger a first refresh state to
+        // set the initial state
+        mLockTile.refreshState();
+
+        mTestableLooper.processAllMessages();
+
+        mContext.setMockPackageManager(mPackageManager);
+        doReturn(PACKAGE_NAME).when(mPackageManager).getRotationResolverPackageName();
+        doReturn(PackageManager.PERMISSION_GRANTED).when(mPackageManager).checkPermission(
+                Manifest.permission.CAMERA, PACKAGE_NAME);
+
+        when(mBatteryController.isPowerSave()).thenReturn(false);
+        when(mPrivacyManager.isSensorPrivacyEnabled(CAMERA)).thenReturn(false);
+        enableAutoRotation();
+        enableCameraBasedRotation();
+
+        mLockTile.refreshState();
+        mTestableLooper.processAllMessages();
+    }
+
+    @Test
+    public void testSecondaryString_cameraRotateOn_returnsFaceBased() {
+        assertEquals(mContext.getString(R.string.rotation_lock_camera_rotation_on),
+                mLockTile.getState().secondaryLabel.toString());
+    }
+
+    @Test
+    public void testSecondaryString_rotateOff_isEmpty() {
+        disableAutoRotation();
+
+        mLockTile.refreshState();
+        mTestableLooper.processAllMessages();
+
+        assertEquals("", mLockTile.getState().secondaryLabel.toString());
+    }
+
+    @Test
+    public void testSecondaryString_cameraRotateOff_isEmpty() {
+        disableCameraBasedRotation();
+
+        mLockTile.refreshState();
+        mTestableLooper.processAllMessages();
+
+        assertEquals("", mLockTile.getState().secondaryLabel.toString());
+    }
+
+    @Test
+    public void testSecondaryString_powerSaveEnabled_isEmpty() {
+        when(mBatteryController.isPowerSave()).thenReturn(true);
+
+        mLockTile.refreshState();
+        mTestableLooper.processAllMessages();
+
+        assertEquals("", mLockTile.getState().secondaryLabel.toString());
+    }
+
+    @Test
+    public void testSecondaryString_cameraDisabled_isEmpty() {
+        when(mPrivacyManager.isSensorPrivacyEnabled(CAMERA)).thenReturn(true);
+
+        mLockTile.refreshState();
+        mTestableLooper.processAllMessages();
+
+        assertEquals("", mLockTile.getState().secondaryLabel.toString());
+    }
+
+    @Test
+    public void testSecondaryString_noCameraPermission_isEmpty() {
+        doReturn(PackageManager.PERMISSION_DENIED).when(mPackageManager).checkPermission(
+                Manifest.permission.CAMERA, PACKAGE_NAME);
+
+        mLockTile.refreshState();
+        mTestableLooper.processAllMessages();
+
+        assertEquals("", mLockTile.getState().secondaryLabel.toString());
+    }
+
+    private void enableAutoRotation() {
+        when(mRotationPolicyWrapper.isRotationLocked()).thenReturn(false);
+    }
+
+    private void disableAutoRotation() {
+        when(mRotationPolicyWrapper.isRotationLocked()).thenReturn(true);
+    }
+
+    private void enableCameraBasedRotation() {
+        when(mRotationPolicyWrapper.isCameraRotationEnabled()).thenReturn(true);
+    }
+
+    private void disableCameraBasedRotation() {
+        when(mRotationPolicyWrapper.isCameraRotationEnabled()).thenReturn(false);
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java
index 9bf8775..8a38847 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java
@@ -45,6 +45,7 @@
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.policy.HeadsUpManagerLogger;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -86,6 +87,7 @@
             super(mock(HeadsUpManagerLogger.class));
             mMinimumDisplayTime = TEST_MINIMUM_DISPLAY_TIME;
             mAutoDismissNotificationDecay = TEST_AUTO_DISMISS_TIME;
+            mHandler.removeCallbacksAndMessages(null);
             mHandler = mTestHandler;
         }
 
@@ -145,6 +147,11 @@
         mAlertingNotificationManager = createAlertingNotificationManager();
     }
 
+    @After
+    public void tearDown() {
+        mTestHandler.removeCallbacksAndMessages(null);
+    }
+
     @Test
     public void testShowNotification_addsEntry() {
         mAlertingNotificationManager.showNotification(mEntry);
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 e427d53..7f35732 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
@@ -81,6 +81,7 @@
 import com.android.systemui.dock.DockManager;
 import com.android.systemui.keyguard.KeyguardIndication;
 import com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController;
+import com.android.systemui.keyguard.ScreenLifecycle;
 import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
@@ -154,6 +155,8 @@
     private IActivityManager mIActivityManager;
     @Mock
     private KeyguardBypassController mKeyguardBypassController;
+    @Mock
+    private ScreenLifecycle mScreenLifecycle;
     @Captor
     private ArgumentCaptor<DockManager.AlignmentStateListener> mAlignmentListener;
     @Captor
@@ -195,7 +198,7 @@
                 R.string.do_financed_disclosure_with_name, ORGANIZATION_NAME);
 
         when(mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true);
-        when(mKeyguardUpdateMonitor.isScreenOn()).thenReturn(true);
+        when(mScreenLifecycle.getScreenState()).thenReturn(ScreenLifecycle.SCREEN_ON);
         when(mKeyguardUpdateMonitor.isUserUnlocked(anyInt())).thenReturn(true);
 
         when(mIndicationArea.findViewById(R.id.keyguard_indication_text_bottom))
@@ -225,8 +228,8 @@
         mController = new KeyguardIndicationController(mContext, mWakeLockBuilder,
                 mKeyguardStateController, mStatusBarStateController, mKeyguardUpdateMonitor,
                 mDockManager, mBroadcastDispatcher, mDevicePolicyManager, mIBatteryStats,
-                mUserManager, mExecutor, mFalsingManager, mLockPatternUtils, mIActivityManager,
-                mKeyguardBypassController);
+                mUserManager, mExecutor, mFalsingManager, mLockPatternUtils, mScreenLifecycle,
+                mIActivityManager, mKeyguardBypassController);
         mController.init();
         mController.setIndicationArea(mIndicationArea);
         verify(mStatusBarStateController).addCallback(mStatusBarStateListenerCaptor.capture());
@@ -702,7 +705,6 @@
         // 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);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorControllerTest.kt
index c74437f..3a60c04 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorControllerTest.kt
@@ -4,6 +4,7 @@
 import android.testing.TestableLooper
 import android.testing.TestableLooper.RunWithLooper
 import androidx.test.filters.SmallTest
+import com.android.internal.jank.InteractionJankMonitor
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
 import com.android.systemui.statusbar.notification.row.NotificationTestHelper
@@ -29,6 +30,7 @@
     @Mock lateinit var notificationShadeWindowViewController: NotificationShadeWindowViewController
     @Mock lateinit var notificationListContainer: NotificationListContainer
     @Mock lateinit var headsUpManager: HeadsUpManagerPhone
+    @Mock lateinit var jankMonitor: InteractionJankMonitor
 
     private lateinit var notificationTestHelper: NotificationTestHelper
     private lateinit var notification: ExpandableNotificationRow
@@ -49,7 +51,8 @@
                 notificationShadeWindowViewController,
                 notificationListContainer,
                 headsUpManager,
-                notification
+                notification,
+                jankMonitor
         )
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.java
index a3569e4..a11b46d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.java
@@ -19,8 +19,11 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.BDDMockito.given;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -44,6 +47,8 @@
 import com.android.systemui.statusbar.notification.row.NotifBindPipeline.BindCallback;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
+import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.time.FakeSystemClock;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -52,6 +57,8 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.util.ArrayList;
+
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper
@@ -75,6 +82,9 @@
     @Mock private NodeController mHeaderController;
 
     private NotificationEntry mEntry;
+    private final FakeSystemClock mClock = new FakeSystemClock();
+    private final FakeExecutor mExecutor = new FakeExecutor(mClock);
+    private final ArrayList<NotificationEntry> mHuns = new ArrayList();
 
     @Before
     public void setUp() {
@@ -85,7 +95,8 @@
                 mHeadsUpViewBinder,
                 mNotificationInterruptStateProvider,
                 mRemoteInputManager,
-                mHeaderController);
+                mHeaderController,
+                mExecutor);
 
         mCoordinator.attach(mNotifPipeline);
 
@@ -105,6 +116,16 @@
                 notifLifetimeExtenderCaptor.capture());
         verify(mHeadsUpManager).addListener(headsUpChangedListenerCaptor.capture());
 
+        given(mHeadsUpManager.getAllEntries()).willAnswer(i -> mHuns.stream());
+        given(mHeadsUpManager.isAlerting(anyString())).willAnswer(i -> {
+            String key = i.getArgument(0);
+            for (NotificationEntry entry : mHuns) {
+                if (entry.getKey().equals(key)) return true;
+            }
+            return false;
+        });
+        when(mHeadsUpManager.getEarliestRemovalTime(anyString())).thenReturn(1000L);
+
         mCollectionListener = notifCollectionCaptor.getValue();
         mNotifPromoter = notifPromoterCaptor.getValue();
         mNotifLifetimeExtender = notifLifetimeExtenderCaptor.getValue();
@@ -116,63 +137,64 @@
     }
 
     @Test
+    public void testCancelStickyNotification() {
+        when(mHeadsUpManager.isSticky(anyString())).thenReturn(true);
+        addHUN(mEntry);
+        when(mHeadsUpManager.getEarliestRemovalTime(anyString())).thenReturn(1000L, 0L);
+        assertTrue(mNotifLifetimeExtender.shouldExtendLifetime(mEntry, 0));
+        mClock.advanceTime(1000L);
+        mExecutor.runAllReady();
+        verify(mHeadsUpManager, times(1))
+                .removeNotification(anyString(), eq(true));
+    }
+
+    @Test
+    public void testCancelUpdatedStickyNotification() {
+        when(mHeadsUpManager.isSticky(anyString())).thenReturn(true);
+        addHUN(mEntry);
+        when(mHeadsUpManager.getEarliestRemovalTime(anyString())).thenReturn(1000L, 500L);
+        assertTrue(mNotifLifetimeExtender.shouldExtendLifetime(mEntry, 0));
+        mClock.advanceTime(1000L);
+        mExecutor.runAllReady();
+        verify(mHeadsUpManager, times(0))
+                .removeNotification(anyString(), eq(true));
+    }
+
+    @Test
     public void testPromotesCurrentHUN() {
         // GIVEN the current HUN is set to mEntry
-        setCurrentHUN(mEntry);
+        addHUN(mEntry);
 
         // THEN only promote the current HUN, mEntry
         assertTrue(mNotifPromoter.shouldPromoteToTopLevel(mEntry));
-        assertFalse(mNotifPromoter.shouldPromoteToTopLevel(new NotificationEntryBuilder().build()));
+        assertFalse(mNotifPromoter.shouldPromoteToTopLevel(new NotificationEntryBuilder()
+                .setPkg("test-package2")
+                .build()));
     }
 
     @Test
     public void testIncludeInSectionCurrentHUN() {
         // GIVEN the current HUN is set to mEntry
-        setCurrentHUN(mEntry);
+        addHUN(mEntry);
 
         // THEN only section the current HUN, mEntry
         assertTrue(mNotifSectioner.isInSection(mEntry));
-        assertFalse(mNotifSectioner.isInSection(new NotificationEntryBuilder().build()));
+        assertFalse(mNotifSectioner.isInSection(new NotificationEntryBuilder()
+                .setPkg("test-package")
+                .build()));
     }
 
     @Test
     public void testLifetimeExtendsCurrentHUN() {
         // GIVEN there is a HUN, mEntry
-        setCurrentHUN(mEntry);
+        addHUN(mEntry);
 
         // THEN only the current HUN, mEntry, should be lifetimeExtended
         assertTrue(mNotifLifetimeExtender.shouldExtendLifetime(mEntry, /* cancellationReason */ 0));
         assertFalse(mNotifLifetimeExtender.shouldExtendLifetime(
-                new NotificationEntryBuilder().build(), /* cancellationReason */ 0));
-    }
-
-    @Test
-    public void testLifetimeExtensionEndsOnNewHUN() {
-        // GIVEN there was a HUN that was lifetime extended
-        setCurrentHUN(mEntry);
-        assertTrue(mNotifLifetimeExtender.shouldExtendLifetime(
-                mEntry, /* cancellation reason */ 0));
-
-        // WHEN there's a new HUN
-        NotificationEntry newHUN = new NotificationEntryBuilder().build();
-        setCurrentHUN(newHUN);
-
-        // THEN the old entry's lifetime extension should be cancelled
-        verify(mEndLifetimeExtension).onEndLifetimeExtension(mNotifLifetimeExtender, mEntry);
-    }
-
-    @Test
-    public void testLifetimeExtensionEndsOnNoHUNs() {
-        // GIVEN there was a HUN that was lifetime extended
-        setCurrentHUN(mEntry);
-        assertTrue(mNotifLifetimeExtender.shouldExtendLifetime(
-                mEntry, /* cancellation reason */ 0));
-
-        // WHEN there's no longer a HUN
-        setCurrentHUN(null);
-
-        // THEN the old entry's lifetime extension should be cancelled
-        verify(mEndLifetimeExtension).onEndLifetimeExtension(mNotifLifetimeExtender, mEntry);
+                new NotificationEntryBuilder()
+                        .setPkg("test-package")
+                        .build(), /* cancellationReason */ 0));
     }
 
     @Test
@@ -208,7 +230,7 @@
     @Test
     public void testOnEntryRemovedRemovesHeadsUpNotification() {
         // GIVEN the current HUN is mEntry
-        setCurrentHUN(mEntry);
+        addHUN(mEntry);
 
         // WHEN mEntry is removed from the notification collection
         mCollectionListener.onEntryRemoved(mEntry, /* cancellation reason */ 0);
@@ -218,12 +240,9 @@
         verify(mHeadsUpManager).removeNotification(mEntry.getKey(), false);
     }
 
-    private void setCurrentHUN(NotificationEntry entry) {
+    private void addHUN(NotificationEntry entry) {
+        mHuns.add(entry);
         when(mHeadsUpManager.getTopEntry()).thenReturn(entry);
-        when(mHeadsUpManager.isAlerting(any())).thenReturn(false);
-        if (entry != null) {
-            when(mHeadsUpManager.isAlerting(entry.getKey())).thenReturn(true);
-        }
         mOnHeadsUpChangedListener.onHeadsUpStateChanged(entry, entry != null);
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinatorTest.java
index c5dc2b4..3ddff49 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinatorTest.java
@@ -120,7 +120,7 @@
     private NotifFilter captureFilter(MediaCoordinator coordinator) {
         ArgumentCaptor<NotifFilter> filterCaptor = ArgumentCaptor.forClass(NotifFilter.class);
         coordinator.attach(mNotifPipeline);
-        verify(mNotifPipeline).addFinalizeFilter(filterCaptor.capture());
+        verify(mNotifPipeline).addPreGroupFilter(filterCaptor.capture());
         return filterCaptor.getValue();
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerLegacyTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerLegacyTest.java
index 2dfb9fc..429d2ed 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerLegacyTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerLegacyTest.java
@@ -60,6 +60,7 @@
 
 import com.google.android.collect.Lists;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -131,6 +132,11 @@
         verify(mNotifPipeline, never()).addCollectionListener(any());
     }
 
+    @After
+    public void tearDown() {
+        mLogger.mHandler.removeCallbacksAndMessages(null);
+    }
+
     @Test
     public void testOnChildLocationsChangedReportsVisibilityChanged() throws Exception {
         NotificationVisibility[] newlyVisibleKeys = {
@@ -281,6 +287,7 @@
                     mNotificationPanelLoggerFake
             );
             mBarService = barService;
+            mHandler.removeCallbacksAndMessages(null);
             // Make this on the current thread so we can wait for it during tests.
             mHandler = Handler.createAsync(Looper.myLooper());
         }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
index 4d861f9..b69bd8d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
@@ -60,6 +60,7 @@
 
 import com.google.android.collect.Lists;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -132,6 +133,11 @@
         verify(mNotifPipeline).addCollectionListener(any());
     }
 
+    @After
+    public void tearDown() {
+        mLogger.mHandler.removeCallbacksAndMessages(null);
+    }
+
     @Test
     public void testOnChildLocationsChangedReportsVisibilityChanged() throws Exception {
         NotificationVisibility[] newlyVisibleKeys = {
@@ -282,6 +288,7 @@
                     mNotificationPanelLoggerFake
             );
             mBarService = barService;
+            mHandler.removeCallbacksAndMessages(null);
             // Make this on the current thread so we can wait for it during tests.
             mHandler = Handler.createAsync(Looper.myLooper());
         }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
index f3eece8..e4721b1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
@@ -36,6 +36,7 @@
 import android.content.Intent;
 import android.content.pm.LauncherApps;
 import android.graphics.drawable.Icon;
+import android.os.Handler;
 import android.os.UserHandle;
 import android.service.notification.StatusBarNotification;
 import android.testing.TestableLooper;
@@ -139,6 +140,8 @@
                 mock(NotificationGroupManagerLegacy.class),
                 mock(ConfigurationControllerImpl.class)
         );
+        mHeadsUpManager.mHandler.removeCallbacksAndMessages(null);
+        mHeadsUpManager.mHandler = new Handler(mTestLooper.getLooper());
         mGroupMembershipManager.setHeadsUpManager(mHeadsUpManager);
         mIconManager = new IconManager(
                 mock(CommonNotifCollection.class),
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 3c84c01..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
@@ -32,7 +32,6 @@
 
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
@@ -44,7 +43,6 @@
 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 FeatureFlags mFeatureFlags;
     private float mSmallRadiusRatio;
 
     @Before
@@ -70,8 +66,7 @@
         mSmallRadiusRatio = resources.getDimension(R.dimen.notification_corner_radius_small)
                 / resources.getDimension(R.dimen.notification_corner_radius);
         mRoundnessManager = new NotificationRoundnessManager(
-                new NotificationSectionsFeatureManager(new DeviceConfigProxy(), mContext),
-                mFeatureFlags);
+                new NotificationSectionsFeatureManager(new DeviceConfigProxy(), mContext));
         allowTestableLooperAsMainThread();
         NotificationTestHelper testHelper = new NotificationTestHelper(
                 mContext,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
index 276f246..4d2c0c3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
@@ -32,6 +32,7 @@
 import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
 import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.inOrder;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
@@ -46,9 +47,7 @@
 
 import androidx.test.filters.SmallTest;
 
-import com.android.systemui.ActivityStarterDelegate;
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.media.KeyguardMediaController;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.StatusBarState;
@@ -56,7 +55,6 @@
 import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.render.SectionHeaderController;
-import com.android.systemui.statusbar.notification.people.PeopleHubViewAdapter;
 import com.android.systemui.statusbar.notification.row.ActivatableNotificationViewController;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.dagger.NotificationRowComponent;
@@ -66,6 +64,7 @@
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.InOrder;
 import org.mockito.Mock;
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
@@ -266,8 +265,9 @@
 
         // THEN the header is first removed from the transient parent before being added to the
         // NSSL.
-        verify(transientParent).removeTransientView(silentHeaderView);
-        verify(mNssl).addView(silentHeaderView, 1);
+        final InOrder inOrder = inOrder(silentHeaderView, mNssl);
+        inOrder.verify(silentHeaderView).removeFromTransientContainer();
+        inOrder.verify(mNssl).addView(eq(silentHeaderView), eq(1));
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
index 7194c66..4cc1be6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
@@ -38,6 +38,7 @@
 
 import androidx.test.filters.SmallTest;
 
+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;
@@ -135,6 +136,7 @@
     @Mock private NotificationRemoteInputManager mRemoteInputManager;
     @Mock private VisualStabilityManager mVisualStabilityManager;
     @Mock private ShadeController mShadeController;
+    @Mock private InteractionJankMonitor mJankMonitor;
 
     @Captor
     private ArgumentCaptor<StatusBarStateController.StateListener> mStateListenerArgumentCaptor;
@@ -188,7 +190,8 @@
                 mLayoutInflater,
                 mRemoteInputManager,
                 mVisualStabilityManager,
-                mShadeController
+                mShadeController,
+                mJankMonitor
         );
 
         when(mNotificationStackScrollLayout.isAttachedToWindow()).thenReturn(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
index e4db072..a14ea54 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
@@ -17,11 +17,12 @@
 package com.android.systemui.statusbar.phone;
 
 import static com.google.common.truth.Truth.assertThat;
+
 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.ArgumentMatchers.eq;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.when;
 
 import android.content.res.Resources;
@@ -32,14 +33,19 @@
 
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.doze.AlwaysOnDisplayPolicy;
 import com.android.systemui.doze.DozeScreenState;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.flags.Flags;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.tuner.TunerService;
+import com.android.systemui.unfold.FoldAodAnimationController;
+import com.android.systemui.unfold.SysUIUnfoldComponent;
 
 import org.junit.Assert;
 import org.junit.Before;
@@ -48,10 +54,11 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.util.Optional;
+
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class DozeParametersTest extends SysuiTestCase {
-
     private DozeParameters mDozeParameters;
 
     @Mock Resources mResources;
@@ -63,10 +70,37 @@
     @Mock private FeatureFlags mFeatureFlags;
     @Mock private DumpManager mDumpManager;
     @Mock private ScreenOffAnimationController mScreenOffAnimationController;
+    @Mock private FoldAodAnimationController mFoldAodAnimationController;
+    @Mock private SysUIUnfoldComponent mSysUIUnfoldComponent;
+    @Mock private UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
+    @Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+    @Mock private StatusBarStateController mStatusBarStateController;
+    @Mock private ConfigurationController mConfigurationController;
+
+    /**
+     * The current value of PowerManager's dozeAfterScreenOff property.
+     *
+     * This property controls whether System UI is controlling the screen off animation. If it's
+     * false (PowerManager should not doze after screen off) then System UI is controlling the
+     * animation. If true, we're not controlling it and PowerManager will doze immediately.
+     */
+    private boolean mPowerManagerDozeAfterScreenOff;
 
     @Before
     public void setup() {
         MockitoAnnotations.initMocks(this);
+
+        // Save the current value set for dozeAfterScreenOff so we can make assertions. This method
+        // is only called if the value changes, which makes it difficult to check that it was set
+        // correctly in tests.
+        doAnswer(invocation -> {
+            mPowerManagerDozeAfterScreenOff = invocation.getArgument(0);
+            return mPowerManagerDozeAfterScreenOff;
+        }).when(mPowerManager).setDozeAfterScreenOff(anyBoolean());
+
+        when(mSysUIUnfoldComponent.getFoldAodAnimationController())
+                .thenReturn(mFoldAodAnimationController);
+
         mDozeParameters = new DozeParameters(
             mResources,
             mAmbientDisplayConfiguration,
@@ -76,23 +110,31 @@
             mTunerService,
             mDumpManager,
             mFeatureFlags,
-            mScreenOffAnimationController
+            mScreenOffAnimationController,
+            Optional.of(mSysUIUnfoldComponent),
+            mUnlockedScreenOffAnimationController,
+            mKeyguardUpdateMonitor,
+            mConfigurationController,
+            mStatusBarStateController
         );
-    }
-    @Test
-    public void testSetControlScreenOffAnimation_setsDozeAfterScreenOff_false() {
-        mDozeParameters.setControlScreenOffAnimation(true);
-        reset(mPowerManager);
-        mDozeParameters.setControlScreenOffAnimation(false);
-        verify(mPowerManager).setDozeAfterScreenOff(eq(true));
+
+        when(mFeatureFlags.isEnabled(Flags.LOCKSCREEN_ANIMATIONS)).thenReturn(true);
+        setAodEnabledForTest(true);
+        setShouldControlUnlockedScreenOffForTest(true);
+        setDisplayNeedsBlankingForTest(false);
     }
 
     @Test
-    public void testSetControlScreenOffAnimation_setsDozeAfterScreenOff_true() {
-        mDozeParameters.setControlScreenOffAnimation(false);
-        reset(mPowerManager);
+    public void testSetControlScreenOffAnimation_setsDozeAfterScreenOff_correctly() {
+        // If we want to control screen off, we do NOT want PowerManager to doze after screen off.
+        // Obviously.
         mDozeParameters.setControlScreenOffAnimation(true);
-        verify(mPowerManager).setDozeAfterScreenOff(eq(false));
+        assertFalse(mPowerManagerDozeAfterScreenOff);
+
+        // If we don't want to control screen off, PowerManager is free to doze after screen off if
+        // that's what'll make it happy.
+        mDozeParameters.setControlScreenOffAnimation(false);
+        assertTrue(mPowerManagerDozeAfterScreenOff);
     }
 
     @Test
@@ -121,35 +163,124 @@
         assertThat(mDozeParameters.getAlwaysOn()).isFalse();
     }
 
+    /**
+     * PowerManager.setDozeAfterScreenOff(true) means we are not controlling screen off, and calling
+     * it with false means we are. Confusing, but sure - make sure that we call PowerManager with
+     * the correct value depending on whether we want to control screen off.
+     */
     @Test
     public void testControlUnlockedScreenOffAnimation_dozeAfterScreenOff_false() {
-        when(mAmbientDisplayConfiguration.alwaysOnEnabled(anyInt())).thenReturn(true);
-        mDozeParameters.onTuningChanged(Settings.Secure.DOZE_ALWAYS_ON, "1");
-        when(mFeatureFlags.isEnabled(Flags.LOCKSCREEN_ANIMATIONS)).thenReturn(true);
-        when(mDozeParameters.shouldControlUnlockedScreenOff()).thenReturn(true);
+        // If AOD is disabled, we shouldn't want to control screen off. Also, let's double check
+        // that when that value is updated, we called through to PowerManager.
+        setAodEnabledForTest(false);
+        assertFalse(mDozeParameters.shouldControlScreenOff());
+        assertTrue(mPowerManagerDozeAfterScreenOff);
 
-        // Trigger the setter for the current value.
-        mDozeParameters.setControlScreenOffAnimation(mDozeParameters.shouldControlScreenOff());
-
-        // We should have asked power manager not to doze after screen off no matter what, since
-        // we're animating and controlling screen off.
-        verify(mPowerManager).setDozeAfterScreenOff(eq(false));
+        // And vice versa...
+        setAodEnabledForTest(true);
+        assertTrue(mDozeParameters.shouldControlScreenOff());
+        assertFalse(mPowerManagerDozeAfterScreenOff);
     }
 
     @Test
     public void testControlUnlockedScreenOffAnimationDisabled_dozeAfterScreenOff() {
-        when(mAmbientDisplayConfiguration.alwaysOnEnabled(anyInt())).thenReturn(true);
-        mDozeParameters.onTuningChanged(Settings.Secure.DOZE_ALWAYS_ON, "1");
+        setShouldControlUnlockedScreenOffForTest(true);
         when(mFeatureFlags.isEnabled(Flags.LOCKSCREEN_ANIMATIONS)).thenReturn(false);
 
         assertFalse(mDozeParameters.shouldControlUnlockedScreenOff());
 
         // Trigger the setter for the current value.
         mDozeParameters.setControlScreenOffAnimation(mDozeParameters.shouldControlScreenOff());
+        assertFalse(mDozeParameters.shouldControlScreenOff());
+    }
 
-        // We should have asked power manager to doze only if we're not controlling screen off
-        // normally.
-        verify(mPowerManager).setDozeAfterScreenOff(
-                eq(!mDozeParameters.shouldControlScreenOff()));
+    @Test
+    public void propagatesAnimateScreenOff_noAlwaysOn() {
+        setAodEnabledForTest(false);
+        setDisplayNeedsBlankingForTest(false);
+
+        mDozeParameters.mKeyguardVisibilityCallback.onKeyguardVisibilityChanged(false);
+        assertFalse(mDozeParameters.shouldControlScreenOff());
+    }
+
+    @Test
+    public void propagatesAnimateScreenOff_alwaysOn() {
+        setAodEnabledForTest(true);
+        setDisplayNeedsBlankingForTest(false);
+        setShouldControlUnlockedScreenOffForTest(false);
+
+        // Take over when the keyguard is visible.
+        mDozeParameters.mKeyguardVisibilityCallback.onKeyguardVisibilityChanged(true);
+        assertTrue(mDozeParameters.shouldControlScreenOff());
+
+        // Do not animate screen-off when keyguard isn't visible.
+        mDozeParameters.mKeyguardVisibilityCallback.onKeyguardVisibilityChanged(false);
+        assertFalse(mDozeParameters.shouldControlScreenOff());
+    }
+
+
+    @Test
+    public void neverAnimateScreenOff_whenNotSupported() {
+        setDisplayNeedsBlankingForTest(true);
+
+        // Never animate if display doesn't support it.
+        mDozeParameters.mKeyguardVisibilityCallback.onKeyguardVisibilityChanged(true);
+        assertFalse(mDozeParameters.shouldControlScreenOff());
+        mDozeParameters.mKeyguardVisibilityCallback.onKeyguardVisibilityChanged(false);
+        assertFalse(mDozeParameters.shouldControlScreenOff());
+    }
+
+
+    @Test
+    public void controlScreenOffTrueWhenKeyguardNotShowingAndControlUnlockedScreenOff() {
+        setShouldControlUnlockedScreenOffForTest(true);
+
+        // Tell doze that keyguard is not visible.
+        mDozeParameters.mKeyguardVisibilityCallback.onKeyguardVisibilityChanged(
+                false /* showing */);
+
+        // Since we're controlling the unlocked screen off animation, verify that we've asked to
+        // control the screen off animation despite being unlocked.
+        assertTrue(mDozeParameters.shouldControlScreenOff());
+    }
+
+
+    @Test
+    public void keyguardVisibility_changesControlScreenOffAnimation() {
+        setShouldControlUnlockedScreenOffForTest(false);
+
+        mDozeParameters.mKeyguardVisibilityCallback.onKeyguardVisibilityChanged(false);
+        assertFalse(mDozeParameters.shouldControlScreenOff());
+        mDozeParameters.mKeyguardVisibilityCallback.onKeyguardVisibilityChanged(true);
+        assertTrue(mDozeParameters.shouldControlScreenOff());
+    }
+
+    @Test
+    public void keyguardVisibility_changesControlScreenOffAnimation_respectsUnlockedScreenOff() {
+        setShouldControlUnlockedScreenOffForTest(true);
+
+        // Even if the keyguard is gone, we should control screen off if we can control unlocked
+        // screen off.
+        mDozeParameters.mKeyguardVisibilityCallback.onKeyguardVisibilityChanged(false);
+        assertTrue(mDozeParameters.shouldControlScreenOff());
+
+        mDozeParameters.mKeyguardVisibilityCallback.onKeyguardVisibilityChanged(true);
+        assertTrue(mDozeParameters.shouldControlScreenOff());
+    }
+
+    private void setDisplayNeedsBlankingForTest(boolean needsBlanking) {
+        when(mResources.getBoolean(
+                com.android.internal.R.bool.config_displayBlanksAfterDoze)).thenReturn(
+                        needsBlanking);
+    }
+
+    private void setAodEnabledForTest(boolean enabled) {
+        when(mAmbientDisplayConfiguration.alwaysOnEnabled(anyInt())).thenReturn(enabled);
+        mDozeParameters.onTuningChanged(Settings.Secure.DOZE_ALWAYS_ON, "");
+    }
+
+    private void setShouldControlUnlockedScreenOffForTest(boolean shouldControl) {
+        when(mUnlockedScreenOffAnimationController.shouldPlayUnlockedScreenOffAnimation())
+                .thenReturn(shouldControl);
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/FoldStateListenerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/FoldStateListenerTest.kt
new file mode 100644
index 0000000..649dc23
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/FoldStateListenerTest.kt
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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 android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.internal.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.phone.FoldStateListener.OnFoldStateChangeListener
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations.initMocks
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class FoldStateListenerTest : SysuiTestCase() {
+
+    @Mock
+    private lateinit var listener: OnFoldStateChangeListener
+    private lateinit var sut: FoldStateListener
+
+    @Before
+    fun setUp() {
+        initMocks(this)
+        setFoldedStates(DEVICE_STATE_FOLDED)
+        setGoToSleepStates(DEVICE_STATE_FOLDED)
+        sut = FoldStateListener(mContext, listener)
+    }
+
+    @Test
+    fun onStateChanged_stateFolded_notifiesWithFoldedAndGoingToSleep() {
+        sut.onStateChanged(DEVICE_STATE_FOLDED)
+
+        verify(listener).onFoldStateChanged(FOLDED, WILL_GO_TO_SLEEP)
+    }
+
+    @Test
+    fun onStateChanged_stateHalfFolded_notifiesWithNotFoldedAndNotGoingToSleep() {
+        sut.onStateChanged(DEVICE_STATE_HALF_FOLDED)
+
+        verify(listener).onFoldStateChanged(NOT_FOLDED, WILL_NOT_SLEEP)
+    }
+
+    @Test
+    fun onStateChanged_stateUnfolded_notifiesWithNotFoldedAndNotGoingToSleep() {
+        sut.onStateChanged(DEVICE_STATE_UNFOLDED)
+
+        verify(listener).onFoldStateChanged(NOT_FOLDED, WILL_NOT_SLEEP)
+    }
+
+    @Test
+    fun onStateChanged_stateUnfoldedThenHalfFolded_notifiesOnce() {
+        sut.onStateChanged(DEVICE_STATE_UNFOLDED)
+        sut.onStateChanged(DEVICE_STATE_HALF_FOLDED)
+
+        verify(listener, times(1)).onFoldStateChanged(NOT_FOLDED, WILL_NOT_SLEEP)
+    }
+
+    @Test
+    fun onStateChanged_stateHalfFoldedThenUnfolded_notifiesOnce() {
+        sut.onStateChanged(DEVICE_STATE_HALF_FOLDED)
+        sut.onStateChanged(DEVICE_STATE_UNFOLDED)
+
+        verify(listener, times(1)).onFoldStateChanged(NOT_FOLDED, WILL_NOT_SLEEP)
+    }
+
+    @Test
+    fun onStateChanged_stateHalfFoldedThenFolded_notifiesTwice() {
+        sut.onStateChanged(DEVICE_STATE_HALF_FOLDED)
+        sut.onStateChanged(DEVICE_STATE_FOLDED)
+
+        val inOrder = Mockito.inOrder(listener)
+        inOrder.verify(listener).onFoldStateChanged(NOT_FOLDED, WILL_NOT_SLEEP)
+        inOrder.verify(listener).onFoldStateChanged(FOLDED, WILL_GO_TO_SLEEP)
+    }
+
+    @Test
+    fun onStateChanged_stateFoldedThenHalfFolded_notifiesTwice() {
+        sut.onStateChanged(DEVICE_STATE_FOLDED)
+        sut.onStateChanged(DEVICE_STATE_HALF_FOLDED)
+
+        val inOrder = Mockito.inOrder(listener)
+        inOrder.verify(listener).onFoldStateChanged(FOLDED, WILL_GO_TO_SLEEP)
+        inOrder.verify(listener).onFoldStateChanged(NOT_FOLDED, WILL_NOT_SLEEP)
+    }
+
+    private fun setGoToSleepStates(vararg states: Int) {
+        mContext.orCreateTestableResources.addOverride(
+            R.array.config_deviceStatesOnWhichToSleep,
+            states
+        )
+    }
+
+    private fun setFoldedStates(vararg states: Int) {
+        mContext.orCreateTestableResources.addOverride(
+            R.array.config_foldedDeviceStates,
+            states
+        )
+    }
+
+    companion object {
+        private const val DEVICE_STATE_FOLDED = 123
+        private const val DEVICE_STATE_HALF_FOLDED = 456
+        private const val DEVICE_STATE_UNFOLDED = 789
+
+        private const val FOLDED = true
+        private const val NOT_FOLDED = false
+
+        private const val WILL_GO_TO_SLEEP = true
+        private const val WILL_NOT_SLEEP = false
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
index 0f419c7..e8b9c7b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
@@ -41,6 +41,7 @@
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.HeadsUpManagerLogger;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Ignore;
 import org.junit.Rule;
@@ -115,9 +116,15 @@
                 mConfigurationController
         );
         super.setUp();
+        mHeadsUpManager.mHandler.removeCallbacksAndMessages(null);
         mHeadsUpManager.mHandler = mTestHandler;
     }
 
+    @After
+    public void tearDown() {
+        mTestHandler.removeCallbacksAndMessages(null);
+    }
+
     @Test
     public void testSnooze() {
         mHeadsUpManager.showNotification(mEntry);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
index e5f2aa7..f391eff 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
@@ -26,6 +26,7 @@
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.verifyZeroInteractions;
@@ -43,7 +44,6 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.keyguard.KeyguardHostViewController;
-import com.android.keyguard.KeyguardRootViewController;
 import com.android.keyguard.KeyguardSecurityModel;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.ViewMediatorCallback;
@@ -64,7 +64,6 @@
 import org.mockito.Mock;
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
-import org.mockito.stubbing.Answer;
 
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
@@ -92,13 +91,10 @@
     @Mock
     private KeyguardSecurityModel mKeyguardSecurityModel;
     @Mock
-    private KeyguardRootViewController mRootViewController;
-    @Mock
-    private ViewGroup mRootView;
-    @Mock
     private KeyguardBouncerComponent.Factory mKeyguardBouncerComponentFactory;
     @Mock
     private KeyguardBouncerComponent mKeyguardBouncerComponent;
+    private ViewGroup mContainer;
     @Rule
     public MockitoRule mRule = MockitoJUnit.rule();
     private Integer mRootVisibility = View.INVISIBLE;
@@ -107,32 +103,22 @@
     @Before
     public void setup() {
         allowTestableLooperAsMainThread();
-        mDependency.injectTestDependency(KeyguardUpdateMonitor.class, mKeyguardUpdateMonitor);
-        mDependency.injectMockDependency(KeyguardStateController.class);
-        when(mRootView.getVisibility()).thenAnswer((Answer<Integer>) invocation -> mRootVisibility);
-        doAnswer(invocation -> {
-            mRootVisibility = invocation.getArgument(0);
-            return null;
-        }).when(mRootView).setVisibility(anyInt());
         when(mKeyguardSecurityModel.getSecurityMode(anyInt()))
                 .thenReturn(KeyguardSecurityModel.SecurityMode.None);
         DejankUtils.setImmediate(true);
-        when(mKeyguardBouncerComponentFactory.create()).thenReturn(mKeyguardBouncerComponent);
+
+        mContainer = spy(new FrameLayout(getContext()));
+        when(mKeyguardBouncerComponentFactory.create(mContainer)).thenReturn(
+                mKeyguardBouncerComponent);
         when(mKeyguardBouncerComponent.getKeyguardHostViewController())
                 .thenReturn(mKeyguardHostViewController);
-        when(mKeyguardBouncerComponent.getKeyguardRootViewController())
-                .thenReturn(mRootViewController);
 
-        when(mRootViewController.getView()).thenReturn(mRootView);
-        when(mRootView.getResources()).thenReturn(mContext.getResources());
-
-        final ViewGroup container = new FrameLayout(getContext());
         mBouncer = new KeyguardBouncer.Factory(getContext(), mViewMediatorCallback,
                 mDismissCallbackRegistry, mFalsingCollector,
                 mKeyguardStateController, mKeyguardUpdateMonitor,
                 mKeyguardBypassController, mHandler, mKeyguardSecurityModel,
                 mKeyguardBouncerComponentFactory)
-                .create(container, mExpansionCallback);
+                .create(mContainer, mExpansionCallback);
     }
 
     @Test
@@ -233,7 +219,7 @@
 
         mBouncer.setExpansion(0);
         verify(mKeyguardHostViewController).onResume();
-        verify(mRootView).announceForAccessibility(any());
+        verify(mContainer).announceForAccessibility(any());
     }
 
     @Test
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 1182695..1827c7f 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
@@ -62,6 +62,7 @@
     private float mPanelExpansion;
     private int mKeyguardStatusBarHeaderHeight;
     private int mKeyguardStatusHeight;
+    private int mUserSwitchHeight;
     private float mDark;
     private float mQsExpansion;
     private int mCutoutTopInset = 0;
@@ -264,8 +265,7 @@
 
     @Test
     public void clockPositionedDependingOnMarginInSplitShade() {
-        when(mResources.getDimensionPixelSize(R.dimen.keyguard_split_shade_top_margin))
-                .thenReturn(400);
+        setSplitShadeTopMargin(400);
         mClockPositionAlgorithm.loadDimens(mResources);
         givenLockScreen();
         mIsSplitShade = true;
@@ -291,6 +291,32 @@
     }
 
     @Test
+    public void notifPaddingAccountsForMultiUserSwitcherInSplitShade() {
+        setSplitShadeTopMargin(100);
+        mUserSwitchHeight = 150;
+        mClockPositionAlgorithm.loadDimens(mResources);
+        givenLockScreen();
+        mIsSplitShade = true;
+        // WHEN the position algorithm is run
+        positionClock();
+        // THEN the notif padding is split shade top margin + user switch height
+        assertThat(mClockPosition.stackScrollerPadding).isEqualTo(250);
+    }
+
+    @Test
+    public void clockDoesntAccountForMultiUserSwitcherInSplitShade() {
+        setSplitShadeTopMargin(100);
+        mUserSwitchHeight = 150;
+        mClockPositionAlgorithm.loadDimens(mResources);
+        givenLockScreen();
+        mIsSplitShade = true;
+        // WHEN the position algorithm is run
+        positionClock();
+        // THEN clockY = split shade top margin
+        assertThat(mClockPosition.clockY).isEqualTo(100);
+    }
+
+    @Test
     public void notifPaddingExpandedAlignedWithClockInSplitShadeMode() {
         givenLockScreen();
         mIsSplitShade = true;
@@ -495,6 +521,11 @@
         assertThat(mClockPosition.clockY).isEqualTo(mCutoutTopInset);
     }
 
+    private void setSplitShadeTopMargin(int value) {
+        when(mResources.getDimensionPixelSize(R.dimen.keyguard_split_shade_top_margin))
+                .thenReturn(value);
+    }
+
     private void givenHighestBurnInOffset() {
         when(BurnInHelperKt.getBurnInOffset(anyInt(), anyBoolean())).then(returnsFirstArg());
     }
@@ -529,7 +560,7 @@
                 mKeyguardStatusBarHeaderHeight,
                 mPanelExpansion,
                 mKeyguardStatusHeight,
-                0 /* userSwitchHeight */,
+                mUserSwitchHeight,
                 0 /* userSwitchPreferredY */,
                 mDark,
                 ZERO_DRAG,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java
index b717d28..9898b4b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java
@@ -51,6 +51,7 @@
 import com.android.systemui.statusbar.policy.HeadsUpManagerLogger;
 import com.android.wm.shell.bubbles.Bubbles;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -111,6 +112,11 @@
         mHeadsUpManager.addListener(mGroupAlertTransferHelper);
     }
 
+    @After
+    public void tearDown() {
+        mHeadsUpManager.mHandler.removeCallbacksAndMessages(null);
+    }
+
     private void mockHasHeadsUpContentView(NotificationEntry entry,
             boolean hasHeadsUpContentView) {
         RowContentBindParams params = new RowContentBindParams();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java
index 1cd9b9e..5ada6d4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java
@@ -141,6 +141,7 @@
 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.statusbar.window.StatusBarWindowStateController;
 import com.android.systemui.unfold.SysUIUnfoldComponent;
 import com.android.systemui.util.concurrency.FakeExecutor;
 import com.android.systemui.util.settings.SecureSettings;
@@ -148,6 +149,7 @@
 import com.android.systemui.wallet.controller.QuickAccessWalletController;
 import com.android.wm.shell.animation.FlingAnimationUtils;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -358,6 +360,8 @@
     private NotificationsQSContainerController mNotificationsQSContainerController;
     @Mock
     private QsFrameTranslateController mQsFrameTranslateController;
+    @Mock
+    private StatusBarWindowStateController mStatusBarWindowStateController;
     private Optional<SysUIUnfoldComponent> mSysUIUnfoldComponent = Optional.empty();
     private SysuiStatusBarStateController mStatusBarStateController;
     private NotificationPanelViewController mNotificationPanelViewController;
@@ -366,6 +370,7 @@
     private List<View.OnAttachStateChangeListener> mOnAttachStateChangeListeners;
     private FalsingManagerFake mFalsingManager = new FalsingManagerFake();
     private FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
+    private Handler mMainHandler;
 
     @Before
     public void setup() {
@@ -483,15 +488,19 @@
                 .thenReturn(true);
         reset(mView);
 
+        mMainHandler = new Handler(Looper.getMainLooper());
+
         mNotificationPanelViewController = new NotificationPanelViewController(mView,
                 mResources,
-                new Handler(Looper.getMainLooper()),
+                mMainHandler,
                 mLayoutInflater,
                 mFeatureFlags,
                 coordinator, expansionHandler, mDynamicPrivacyController, mKeyguardBypassController,
                 mFalsingManager, new FalsingCollectorFake(),
                 mNotificationLockscreenUserManager, mNotificationEntryManager,
-                mCommunalStateController, mKeyguardStateController, mStatusBarStateController,
+                mCommunalStateController, mKeyguardStateController,
+                mStatusBarStateController,
+                mStatusBarWindowStateController,
                 mDozeLog, mDozeParameters, mCommandQueue, mVibratorHelper,
                 mLatencyTracker, mPowerManager, mAccessibilityManager, 0, mUpdateMonitor,
                 mCommunalSourceMonitor, mMetricsLogger, mActivityManager, mConfigurationController,
@@ -560,6 +569,12 @@
                 .setHeadsUpAppearanceController(mock(HeadsUpAppearanceController.class));
     }
 
+    @After
+    public void tearDown() {
+        mNotificationPanelViewController.cancelHeightAnimator();
+        mMainHandler.removeCallbacksAndMessages(null);
+    }
+
     @Test
     public void testSetPanelScrimMinFraction() {
         mNotificationPanelViewController.setPanelScrimMinFraction(0.5f);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewControllerTest.kt
new file mode 100644
index 0000000..12e71af
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewControllerTest.kt
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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 android.testing.AndroidTestingRunner
+import android.testing.TestableLooper.RunWithLooper
+import android.view.MotionEvent
+import androidx.test.filters.SmallTest
+import com.android.keyguard.LockIconViewController
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.classifier.FalsingCollectorFake
+import com.android.systemui.dock.DockManager
+import com.android.systemui.statusbar.LockscreenShadeTransitionController
+import com.android.systemui.statusbar.NotificationShadeDepthController
+import com.android.systemui.statusbar.NotificationShadeWindowController
+import com.android.systemui.statusbar.SysuiStatusBarStateController
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
+import com.android.systemui.statusbar.phone.NotificationShadeWindowView.InteractionEventHandler
+import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager
+import com.android.systemui.statusbar.window.StatusBarWindowStateController
+import com.android.systemui.tuner.TunerService
+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.MockitoAnnotations
+import org.mockito.Mockito.anyFloat
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when` as whenever
+
+@RunWith(AndroidTestingRunner::class)
+@RunWithLooper(setAsMainLooper = true)
+@SmallTest
+class NotificationShadeWindowViewControllerTest : SysuiTestCase() {
+    private lateinit var mController: NotificationShadeWindowViewController
+
+    @Mock
+    private lateinit var mView: NotificationShadeWindowView
+    @Mock
+    private lateinit var mTunerService: TunerService
+    @Mock
+    private lateinit var mStatusBarStateController: SysuiStatusBarStateController
+    @Mock
+    private lateinit var mStatusBar: StatusBar
+    @Mock
+    private lateinit var mDockManager: DockManager
+    @Mock
+    private lateinit var mNotificationPanelViewController: NotificationPanelViewController
+    @Mock
+    private lateinit var mNotificationShadeDepthController: NotificationShadeDepthController
+    @Mock
+    private lateinit var mNotificationShadeWindowController: NotificationShadeWindowController
+    @Mock
+    private lateinit var stackScrollLayoutController: NotificationStackScrollLayoutController
+    @Mock
+    private lateinit var mStatusBarKeyguardViewManager: StatusBarKeyguardViewManager
+    @Mock
+    private lateinit var mStatusBarWindowStateController: StatusBarWindowStateController
+    @Mock
+    private lateinit var mLockscreenShadeTransitionController: LockscreenShadeTransitionController
+    @Mock
+    private lateinit var mLockIconViewController: LockIconViewController
+    @Mock
+    private lateinit var mPhoneStatusBarViewController: PhoneStatusBarViewController
+
+    private lateinit var mInteractionEventHandlerCaptor: ArgumentCaptor<InteractionEventHandler>
+    private lateinit var mInteractionEventHandler: InteractionEventHandler
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+        whenever(mView.bottom).thenReturn(VIEW_BOTTOM)
+
+        mController = NotificationShadeWindowViewController(
+            mLockscreenShadeTransitionController,
+            FalsingCollectorFake(),
+            mTunerService,
+            mStatusBarStateController,
+            mDockManager,
+            mNotificationShadeDepthController,
+            mView,
+            mNotificationPanelViewController,
+            PanelExpansionStateManager(),
+            stackScrollLayoutController,
+            mStatusBarKeyguardViewManager,
+            mStatusBarWindowStateController,
+            mLockIconViewController
+        )
+        mController.setupExpandedStatusBar()
+        mController.setService(mStatusBar, mNotificationShadeWindowController)
+
+        mInteractionEventHandlerCaptor =
+            ArgumentCaptor.forClass(InteractionEventHandler::class.java)
+        verify(mView).setInteractionEventHandler(mInteractionEventHandlerCaptor.capture())
+            mInteractionEventHandler = mInteractionEventHandlerCaptor.value
+    }
+
+    // Note: So far, these tests only cover interactions with the status bar view controller. More
+    // tests need to be added to test the rest of handleDispatchTouchEvent.
+
+    @Test
+    fun handleDispatchTouchEvent_nullStatusBarViewController_returnsFalse() {
+        mController.setStatusBarViewController(null)
+
+        val returnVal = mInteractionEventHandler.handleDispatchTouchEvent(downEv)
+
+        assertThat(returnVal).isFalse()
+    }
+
+    @Test
+    fun handleDispatchTouchEvent_downTouchBelowView_sendsTouchToSb() {
+        mController.setStatusBarViewController(mPhoneStatusBarViewController)
+        val ev = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, VIEW_BOTTOM + 4f, 0)
+        whenever(mPhoneStatusBarViewController.sendTouchToView(ev)).thenReturn(true)
+
+        val returnVal = mInteractionEventHandler.handleDispatchTouchEvent(ev)
+
+        verify(mPhoneStatusBarViewController).sendTouchToView(ev)
+        assertThat(returnVal).isTrue()
+    }
+
+    @Test
+    fun handleDispatchTouchEvent_downTouchBelowViewThenAnotherTouch_sendsTouchToSb() {
+        mController.setStatusBarViewController(mPhoneStatusBarViewController)
+        val downEvBelow = MotionEvent.obtain(
+            0L, 0L, MotionEvent.ACTION_DOWN, 0f, VIEW_BOTTOM + 4f, 0
+        )
+        mInteractionEventHandler.handleDispatchTouchEvent(downEvBelow)
+
+        val nextEvent = MotionEvent.obtain(
+            0L, 0L, MotionEvent.ACTION_MOVE, 0f, VIEW_BOTTOM + 5f, 0
+        )
+        whenever(mPhoneStatusBarViewController.sendTouchToView(nextEvent)).thenReturn(true)
+
+        val returnVal = mInteractionEventHandler.handleDispatchTouchEvent(nextEvent)
+
+        verify(mPhoneStatusBarViewController).sendTouchToView(nextEvent)
+        assertThat(returnVal).isTrue()
+    }
+
+    @Test
+    fun handleDispatchTouchEvent_downAndPanelCollapsedAndInSbBoundAndSbWindowShow_sendsTouchToSb() {
+        mController.setStatusBarViewController(mPhoneStatusBarViewController)
+        whenever(mStatusBarWindowStateController.windowIsShowing()).thenReturn(true)
+        whenever(mNotificationPanelViewController.isFullyCollapsed).thenReturn(true)
+        whenever(mPhoneStatusBarViewController.touchIsWithinView(anyFloat(), anyFloat()))
+            .thenReturn(true)
+        whenever(mPhoneStatusBarViewController.sendTouchToView(downEv)).thenReturn(true)
+
+        val returnVal = mInteractionEventHandler.handleDispatchTouchEvent(downEv)
+
+        verify(mPhoneStatusBarViewController).sendTouchToView(downEv)
+        assertThat(returnVal).isTrue()
+    }
+
+    @Test
+    fun handleDispatchTouchEvent_panelNotCollapsed_returnsNull() {
+        mController.setStatusBarViewController(mPhoneStatusBarViewController)
+        whenever(mStatusBarWindowStateController.windowIsShowing()).thenReturn(true)
+        whenever(mPhoneStatusBarViewController.touchIsWithinView(anyFloat(), anyFloat()))
+            .thenReturn(true)
+        // Item we're testing
+        whenever(mNotificationPanelViewController.isFullyCollapsed).thenReturn(false)
+
+        val returnVal = mInteractionEventHandler.handleDispatchTouchEvent(downEv)
+
+        verify(mPhoneStatusBarViewController, never()).sendTouchToView(downEv)
+        assertThat(returnVal).isNull()
+    }
+
+    @Test
+    fun handleDispatchTouchEvent_touchNotInSbBounds_returnsNull() {
+        mController.setStatusBarViewController(mPhoneStatusBarViewController)
+        whenever(mStatusBarWindowStateController.windowIsShowing()).thenReturn(true)
+        whenever(mNotificationPanelViewController.isFullyCollapsed).thenReturn(true)
+        // Item we're testing
+        whenever(mPhoneStatusBarViewController.touchIsWithinView(anyFloat(), anyFloat()))
+            .thenReturn(false)
+
+        val returnVal = mInteractionEventHandler.handleDispatchTouchEvent(downEv)
+
+        verify(mPhoneStatusBarViewController, never()).sendTouchToView(downEv)
+        assertThat(returnVal).isNull()
+    }
+
+    @Test
+    fun handleDispatchTouchEvent_sbWindowNotShowing_noSendTouchToSbAndReturnsTrue() {
+        mController.setStatusBarViewController(mPhoneStatusBarViewController)
+        whenever(mNotificationPanelViewController.isFullyCollapsed).thenReturn(true)
+        whenever(mPhoneStatusBarViewController.touchIsWithinView(anyFloat(), anyFloat()))
+            .thenReturn(true)
+        // Item we're testing
+        whenever(mStatusBarWindowStateController.windowIsShowing()).thenReturn(false)
+
+        val returnVal = mInteractionEventHandler.handleDispatchTouchEvent(downEv)
+
+        verify(mPhoneStatusBarViewController, never()).sendTouchToView(downEv)
+        assertThat(returnVal).isTrue()
+    }
+
+    @Test
+    fun handleDispatchTouchEvent_downEventSentToSbThenAnotherEvent_sendsTouchToSb() {
+        mController.setStatusBarViewController(mPhoneStatusBarViewController)
+        whenever(mStatusBarWindowStateController.windowIsShowing()).thenReturn(true)
+        whenever(mNotificationPanelViewController.isFullyCollapsed).thenReturn(true)
+        whenever(mPhoneStatusBarViewController.touchIsWithinView(anyFloat(), anyFloat()))
+            .thenReturn(true)
+
+        // Down event first
+        mInteractionEventHandler.handleDispatchTouchEvent(downEv)
+
+        // Then another event
+        val nextEvent = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_MOVE, 0f, 0f, 0)
+        whenever(mPhoneStatusBarViewController.sendTouchToView(nextEvent)).thenReturn(true)
+
+        val returnVal = mInteractionEventHandler.handleDispatchTouchEvent(nextEvent)
+
+        verify(mPhoneStatusBarViewController).sendTouchToView(nextEvent)
+        assertThat(returnVal).isTrue()
+    }
+}
+
+private val downEv = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0)
+private const val VIEW_BOTTOM = 100
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 1adba6e..d885da8 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
@@ -37,24 +37,15 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.classifier.FalsingCollectorFake;
 import com.android.systemui.dock.DockManager;
-import com.android.systemui.doze.DozeLog;
-import com.android.systemui.shared.plugins.PluginManager;
-import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.DragDownHelper;
 import com.android.systemui.statusbar.LockscreenShadeTransitionController;
-import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationShadeDepthController;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
-import com.android.systemui.statusbar.PulseExpansionHandler;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
-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.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
 import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
-import com.android.systemui.statusbar.policy.KeyguardStateController;
-import com.android.systemui.statusbar.window.StatusBarWindowController;
+import com.android.systemui.statusbar.window.StatusBarWindowStateController;
 import com.android.systemui.tuner.TunerService;
 
 import org.junit.Before;
@@ -73,29 +64,19 @@
     private NotificationShadeWindowView mView;
     private NotificationShadeWindowViewController mController;
 
-    @Mock private NotificationWakeUpCoordinator mCoordinator;
-    @Mock private PulseExpansionHandler mPulseExpansionHandler;
-    @Mock private DynamicPrivacyController mDynamicPrivacyController;
-    @Mock private KeyguardBypassController mBypassController;
-    @Mock private PluginManager mPluginManager;
     @Mock private TunerService mTunerService;
     @Mock private DragDownHelper mDragDownHelper;
-    @Mock private KeyguardStateController mKeyguardStateController;
     @Mock private SysuiStatusBarStateController mStatusBarStateController;
     @Mock private ShadeController mShadeController;
-    @Mock private NotificationLockscreenUserManager mNotificationLockScreenUserManager;
-    @Mock private NotificationEntryManager mNotificationEntryManager;
     @Mock private StatusBar mStatusBar;
-    @Mock private DozeLog mDozeLog;
-    @Mock private DozeParameters mDozeParameters;
     @Mock private DockManager mDockManager;
     @Mock private NotificationPanelViewController mNotificationPanelViewController;
     @Mock private NotificationStackScrollLayout mNotificationStackScrollLayout;
     @Mock private NotificationShadeDepthController mNotificationShadeDepthController;
-    @Mock private StatusBarWindowController mStatusBarWindowController;
     @Mock private NotificationShadeWindowController mNotificationShadeWindowController;
     @Mock private NotificationStackScrollLayoutController mNotificationStackScrollLayoutController;
     @Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
+    @Mock private StatusBarWindowStateController mStatusBarWindowStateController;
     @Mock private LockscreenShadeTransitionController mLockscreenShadeTransitionController;
     @Mock private LockIconViewController mLockIconViewController;
 
@@ -117,30 +98,18 @@
         when(mDockManager.isDocked()).thenReturn(false);
 
         mController = new NotificationShadeWindowViewController(
-                mCoordinator,
-                mPulseExpansionHandler,
-                mDynamicPrivacyController,
-                mBypassController,
                 mLockscreenShadeTransitionController,
                 new FalsingCollectorFake(),
-                mPluginManager,
                 mTunerService,
-                mNotificationLockScreenUserManager,
-                mNotificationEntryManager,
-                mKeyguardStateController,
                 mStatusBarStateController,
-                mDozeLog,
-                mDozeParameters,
-                new CommandQueue(mContext),
-                mShadeController,
                 mDockManager,
                 mNotificationShadeDepthController,
                 mView,
                 mNotificationPanelViewController,
                 new PanelExpansionStateManager(),
-                mStatusBarWindowController,
                 mNotificationStackScrollLayoutController,
                 mStatusBarKeyguardViewManager,
+                mStatusBarWindowStateController,
                 mLockIconViewController);
         mController.setupExpandedStatusBar();
         mController.setService(mStatusBar, mNotificationShadeWindowController);
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 235de1e..c65a6b6 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
@@ -77,9 +77,10 @@
             val parent = FrameLayout(mContext) // add parent to keep layout params
             view = LayoutInflater.from(mContext)
                 .inflate(R.layout.status_bar, parent, false) as PhoneStatusBarView
+            view.setLeftTopRightBottom(VIEW_LEFT, VIEW_TOP, VIEW_RIGHT, VIEW_BOTTOM)
         }
 
-        controller = createController(view)
+        controller = createAndInitController(view)
     }
 
     @Test
@@ -99,8 +100,7 @@
         val view = createViewMock()
         val argumentCaptor = ArgumentCaptor.forClass(OnPreDrawListener::class.java)
         unfoldConfig.isEnabled = true
-        controller = createController(view)
-        controller.init()
+        controller = createAndInitController(view)
 
         verify(view.viewTreeObserver).addOnPreDrawListener(argumentCaptor.capture())
         argumentCaptor.value.onPreDraw()
@@ -108,6 +108,64 @@
         verify(moveFromCenterAnimation).onViewsReady(any())
     }
 
+    @Test
+    fun touchIsWithinView_inBounds_returnsTrue() {
+        val view = createViewMockWithScreenLocation()
+        controller = createAndInitController(view)
+
+        assertThat(controller.touchIsWithinView(VIEW_LEFT + 1f, VIEW_TOP + 1f)).isTrue()
+    }
+
+    @Test
+    fun touchIsWithinView_onTopLeftCorner_returnsTrue() {
+        val view = createViewMockWithScreenLocation()
+        controller = createAndInitController(view)
+
+        assertThat(controller.touchIsWithinView(VIEW_LEFT.toFloat(), VIEW_TOP.toFloat())).isTrue()
+    }
+
+    @Test
+    fun touchIsWithinView_onBottomRightCorner_returnsTrue() {
+        val view = createViewMockWithScreenLocation()
+        controller = createAndInitController(view)
+
+        assertThat(controller.touchIsWithinView(
+            VIEW_RIGHT.toFloat(), VIEW_BOTTOM.toFloat())
+        ).isTrue()
+    }
+
+    @Test
+    fun touchIsWithinView_xTooSmall_returnsFalse() {
+        val view = createViewMockWithScreenLocation()
+        controller = createAndInitController(view)
+
+        assertThat(controller.touchIsWithinView(VIEW_LEFT - 1f, VIEW_TOP + 1f)).isFalse()
+    }
+
+    @Test
+    fun touchIsWithinView_xTooLarge_returnsFalse() {
+        val view = createViewMockWithScreenLocation()
+        controller = createAndInitController(view)
+
+        assertThat(controller.touchIsWithinView(VIEW_RIGHT + 1f, VIEW_TOP + 1f)).isFalse()
+    }
+
+    @Test
+    fun touchIsWithinView_yTooSmall_returnsFalse() {
+        val view = createViewMockWithScreenLocation()
+        controller = createAndInitController(view)
+
+        assertThat(controller.touchIsWithinView(VIEW_LEFT + 1f, VIEW_TOP - 1f)).isFalse()
+    }
+
+    @Test
+    fun touchIsWithinView_yTooLarge_returnsFalse() {
+        val view = createViewMockWithScreenLocation()
+        controller = createAndInitController(view)
+
+        assertThat(controller.touchIsWithinView(VIEW_LEFT + 1f, VIEW_BOTTOM + 1f)).isFalse()
+    }
+
     private fun createViewMock(): PhoneStatusBarView {
         val view = spy(view)
         val viewTreeObserver = mock(ViewTreeObserver::class.java)
@@ -116,12 +174,23 @@
         return view
     }
 
-    private fun createController(view: PhoneStatusBarView): PhoneStatusBarViewController {
+    private fun createViewMockWithScreenLocation(): PhoneStatusBarView {
+        val view = spy(view)
+        val location = IntArray(2)
+        location[0] = VIEW_LEFT
+        location[1] = VIEW_TOP
+        `when`(view.locationOnScreen).thenReturn(location)
+        return view
+    }
+
+    private fun createAndInitController(view: PhoneStatusBarView): PhoneStatusBarViewController {
         return PhoneStatusBarViewController.Factory(
             Optional.of(sysuiUnfoldComponent),
             Optional.of(progressProvider),
             configurationController
-        ).create(view, touchEventHandler)
+        ).create(view, touchEventHandler).also {
+            it.init()
+        }
     }
 
     private class UnfoldConfig : UnfoldTransitionConfig {
@@ -142,3 +211,8 @@
         }
     }
 }
+
+private const val VIEW_LEFT = 30
+private const val VIEW_RIGHT = 100
+private const val VIEW_TOP = 40
+private const val VIEW_BOTTOM = 100
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacksTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacksTest.java
index 0131293..aabf923 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacksTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacksTest.java
@@ -36,7 +36,6 @@
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.assist.AssistManager;
-import com.android.systemui.dump.DumpManager;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.DisableFlagsLogger;
@@ -46,8 +45,6 @@
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
-import com.android.systemui.util.concurrency.FakeExecutor;
-import com.android.systemui.util.time.FakeSystemClock;
 import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
 
 import org.junit.Before;
@@ -84,6 +81,7 @@
     @Mock private VibratorHelper mVibratorHelper;
     @Mock private Vibrator mVibrator;
     @Mock private LightBarController mLightBarController;
+    @Mock private StatusBarHideIconsForBouncerManager mStatusBarHideIconsForBouncerManager;
 
     StatusBarCommandQueueCallbacks mSbcqCallbacks;
 
@@ -112,8 +110,7 @@
                 mStatusBarStateController,
                 mNotificationShadeWindowView,
                 mNotificationStackScrollLayoutController,
-                new StatusBarHideIconsForBouncerManager(
-                        mCommandQueue, new FakeExecutor(new FakeSystemClock()), new DumpManager()),
+                mStatusBarHideIconsForBouncerManager,
                 mPowerManager,
                 mVibratorHelper,
                 Optional.of(mVibrator),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
index 07ec0e2..743311f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
@@ -48,6 +48,7 @@
 
 import androidx.test.filters.SmallTest;
 
+import com.android.internal.jank.InteractionJankMonitor;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.statusbar.NotificationVisibility;
 import com.android.internal.widget.LockPatternUtils;
@@ -64,7 +65,6 @@
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.notification.NotifPipelineFlags;
-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.collection.NotifPipeline;
@@ -143,6 +143,8 @@
     private StatusBarNotificationActivityStarter mNotificationActivityStarter;
     @Mock
     private ActivityLaunchAnimator mActivityLaunchAnimator;
+    @Mock
+    private InteractionJankMonitor mJankMonitor;
     private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
 
     private NotificationTestHelper mNotificationTestHelper;
@@ -197,7 +199,8 @@
                 new NotificationLaunchAnimatorControllerProvider(
                         mock(NotificationShadeWindowViewController.class), mock(
                         NotificationListContainer.class),
-                        headsUpManager);
+                        headsUpManager,
+                        mJankMonitor);
 
         mNotificationActivityStarter =
                 new StatusBarNotificationActivityStarter.Builder(
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 9d5b17e..bb8bad3 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
@@ -44,6 +44,7 @@
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
 import android.content.IntentFilter;
+import android.hardware.devicestate.DeviceStateManager;
 import android.hardware.display.AmbientDisplayConfiguration;
 import android.hardware.fingerprint.FingerprintManager;
 import android.metrics.LogMaker;
@@ -69,6 +70,7 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.colorextraction.ColorExtractor;
+import com.android.internal.jank.InteractionJankMonitor;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.logging.testing.FakeMetricsLogger;
 import com.android.internal.statusbar.IStatusBarService;
@@ -147,6 +149,7 @@
 import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
 import com.android.systemui.statusbar.window.StatusBarWindowController;
+import com.android.systemui.statusbar.window.StatusBarWindowStateController;
 import com.android.systemui.util.WallpaperController;
 import com.android.systemui.util.concurrency.FakeExecutor;
 import com.android.systemui.util.concurrency.MessageRouterImpl;
@@ -160,6 +163,7 @@
 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;
 
@@ -174,6 +178,9 @@
 @RunWithLooper(setAsMainLooper = true)
 public class StatusBarTest extends SysuiTestCase {
 
+    private static final int FOLD_STATE_FOLDED = 0;
+    private static final int FOLD_STATE_UNFOLDED = 1;
+
     private StatusBar mStatusBar;
     private FakeMetricsLogger mMetricsLogger;
     private PowerManager mPowerManager;
@@ -228,6 +235,7 @@
     @Mock private DynamicPrivacyController mDynamicPrivacyController;
     @Mock private AutoHideController mAutoHideController;
     @Mock private StatusBarWindowController mStatusBarWindowController;
+    @Mock private StatusBarWindowStateController mStatusBarWindowStateController;
     @Mock private NotificationViewHierarchyManager mNotificationViewHierarchyManager;
     @Mock private UserSwitcherController mUserSwitcherController;
     @Mock private NetworkController mNetworkController;
@@ -263,6 +271,7 @@
     @Mock private BrightnessSliderController.Factory mBrightnessSliderFactory;
     @Mock private WallpaperController mWallpaperController;
     @Mock private OngoingCallController mOngoingCallController;
+    @Mock private StatusBarHideIconsForBouncerManager mStatusBarHideIconsForBouncerManager;
     @Mock private LockscreenShadeTransitionController mLockscreenTransitionController;
     @Mock private FeatureFlags mFeatureFlags;
     @Mock private NotificationVisibilityProvider mVisibilityProvider;
@@ -276,6 +285,8 @@
     @Mock private ActivityLaunchAnimator mActivityLaunchAnimator;
     @Mock private NotifPipelineFlags mNotifPipelineFlags;
     @Mock private NotifLiveDataStore mNotifLiveDataStore;
+    @Mock private InteractionJankMonitor mJankMonitor;
+    @Mock private DeviceStateManager mDeviceStateManager;
     private ShadeController mShadeController;
     private final FakeSystemClock mFakeSystemClock = new FakeSystemClock();
     private FakeExecutor mMainExecutor = new FakeExecutor(mFakeSystemClock);
@@ -374,6 +385,7 @@
                 mLightBarController,
                 mAutoHideController,
                 mStatusBarWindowController,
+                mStatusBarWindowStateController,
                 mKeyguardUpdateMonitor,
                 mStatusBarSignalPolicy,
                 mPulseExpansionHandler,
@@ -449,7 +461,7 @@
                 mScreenOffAnimationController,
                 mWallpaperController,
                 mOngoingCallController,
-                new StatusBarHideIconsForBouncerManager(mCommandQueue, mMainExecutor, mDumpManager),
+                mStatusBarHideIconsForBouncerManager,
                 mLockscreenTransitionController,
                 mFeatureFlags,
                 mKeyguardUnlockAnimationController,
@@ -459,7 +471,9 @@
                 mWallpaperManager,
                 Optional.of(mStartingSurface),
                 mActivityLaunchAnimator,
-                mNotifPipelineFlags);
+                mNotifPipelineFlags,
+                mJankMonitor,
+                mDeviceStateManager);
         when(mKeyguardViewMediator.registerStatusBar(
                 any(StatusBar.class),
                 any(NotificationPanelViewController.class),
@@ -942,6 +956,47 @@
         verify(mStatusBarKeyguardViewManager).updateResources();
     }
 
+    @Test
+    public void deviceStateChange_unfolded_shadeOpen_setsLeaveOpenOnKeyguardHide() {
+        setFoldedStates(FOLD_STATE_FOLDED);
+        setGoToSleepStates(FOLD_STATE_FOLDED);
+        when(mNotificationPanelViewController.isFullyExpanded()).thenReturn(true);
+
+        setDeviceState(FOLD_STATE_UNFOLDED);
+
+        verify(mStatusBarStateController).setLeaveOpenOnKeyguardHide(true);
+    }
+
+    @Test
+    public void deviceStateChange_unfolded_shadeClose_doesNotSetLeaveOpenOnKeyguardHide() {
+        setFoldedStates(FOLD_STATE_FOLDED);
+        setGoToSleepStates(FOLD_STATE_FOLDED);
+        when(mNotificationPanelViewController.isFullyExpanded()).thenReturn(false);
+
+        setDeviceState(FOLD_STATE_UNFOLDED);
+
+        verify(mStatusBarStateController, never()).setLeaveOpenOnKeyguardHide(true);
+    }
+
+    private void setDeviceState(int state) {
+        ArgumentCaptor<DeviceStateManager.DeviceStateCallback> callbackCaptor =
+                ArgumentCaptor.forClass(DeviceStateManager.DeviceStateCallback.class);
+        verify(mDeviceStateManager).registerCallback(any(), callbackCaptor.capture());
+        callbackCaptor.getValue().onStateChanged(state);
+    }
+
+    private void setGoToSleepStates(int... states) {
+        mContext.getOrCreateTestableResources().addOverride(
+                com.android.internal.R.array.config_deviceStatesOnWhichToSleep,
+                states);
+    }
+
+    private void setFoldedStates(int... states) {
+        mContext.getOrCreateTestableResources().addOverride(
+                com.android.internal.R.array.config_foldedDeviceStates,
+                states);
+    }
+
     public static class TestableNotificationInterruptStateProviderImpl extends
             NotificationInterruptStateProviderImpl {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt
index a8a33da..24a56bc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt
@@ -21,6 +21,7 @@
 import android.testing.TestableLooper.RunWithLooper
 import android.view.View
 import androidx.test.filters.SmallTest
+import com.android.internal.jank.InteractionJankMonitor
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.keyguard.KeyguardViewMediator
 import com.android.systemui.keyguard.WakefulnessLifecycle
@@ -59,6 +60,8 @@
     private lateinit var wakefulnessLifecycle: WakefulnessLifecycle
     @Mock
     private lateinit var statusBarStateController: StatusBarStateControllerImpl
+    @Mock
+    private lateinit var interactionJankMonitor: InteractionJankMonitor
 
     @Before
     fun setUp() {
@@ -71,7 +74,8 @@
                 dagger.Lazy<KeyguardViewMediator> { keyguardViewMediator },
                 keyguardStateController,
                 dagger.Lazy<DozeParameters> { dozeParameters },
-                globalSettings
+                globalSettings,
+                interactionJankMonitor
         )
         controller.initialize(statusbar, lightRevealScrim)
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
index b97f053..a630840 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
@@ -37,7 +37,6 @@
 
 import com.android.systemui.R;
 import com.android.systemui.SysuiBaseFragmentTest;
-import com.android.systemui.dump.DumpManager;
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.log.LogBuffer;
 import com.android.systemui.log.LogcatEchoTracker;
@@ -57,8 +56,6 @@
 import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController;
 import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
-import com.android.systemui.util.concurrency.FakeExecutor;
-import com.android.systemui.util.time.FakeSystemClock;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -96,6 +93,8 @@
     private HeadsUpAppearanceController mHeadsUpAppearanceController;
     @Mock
     private NotificationPanelViewController mNotificationPanelViewController;
+    @Mock
+    private StatusBarHideIconsForBouncerManager mStatusBarHideIconsForBouncerManager;
 
     public CollapsedStatusBarFragmentTest() {
         super(CollapsedStatusBarFragment.class);
@@ -325,8 +324,7 @@
                 new PanelExpansionStateManager(),
                 mock(FeatureFlags.class),
                 mStatusBarIconController,
-                new StatusBarHideIconsForBouncerManager(
-                        mCommandQueue, new FakeExecutor(new FakeSystemClock()), new DumpManager()),
+                mStatusBarHideIconsForBouncerManager,
                 mKeyguardStateController,
                 mNotificationPanelViewController,
                 mNetworkController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java
index 30717f4..db7b2f2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java
@@ -225,6 +225,11 @@
         }
 
         @Override
+        public boolean isCameraRotationEnabled() {
+            throw new AssertionError("Not implemented");
+        }
+
+        @Override
         public void registerRotationPolicyListener(RotationPolicy.RotationPolicyListener listener,
                 int userHandle) {
             throw new AssertionError("Not implemented");
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java
index 5e852e3..d15ba26 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java
@@ -42,6 +42,7 @@
 import com.android.systemui.statusbar.AlertingNotificationManagerTest;
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -77,9 +78,15 @@
 
         mHeadsUpManager = new TestableHeadsUpManager(mContext);
         super.setUp();
+        mHeadsUpManager.mHandler.removeCallbacksAndMessages(null);
         mHeadsUpManager.mHandler = mTestHandler;
     }
 
+    @After
+    public void tearDown() {
+        mTestHandler.removeCallbacksAndMessages(null);
+    }
+
     @Test
     public void testShowNotification_autoDismissesWithAccessibilityTimeout() {
         doReturn(TEST_A11Y_AUTO_DISMISS_TIME).when(mAccessibilityMgr)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java
index be836d4..087f2e6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java
@@ -15,9 +15,7 @@
 package com.android.systemui.statusbar.policy;
 
 import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.Mockito.doReturn;
 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;
@@ -27,18 +25,25 @@
 import android.location.LocationManager;
 import android.os.Handler;
 import android.os.UserHandle;
+import android.provider.DeviceConfig;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.testing.TestableLooper.RunWithLooper;
 
 import androidx.test.filters.SmallTest;
 
+import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
 import com.android.systemui.BootCompleteCache;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.appops.AppOpItem;
 import com.android.systemui.appops.AppOpsController;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.statusbar.policy.LocationController.LocationChangeCallback;
+import com.android.systemui.util.DeviceConfigProxy;
+import com.android.systemui.util.DeviceConfigProxyFake;
+
+import com.google.common.collect.ImmutableList;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -53,6 +58,7 @@
 
     private LocationControllerImpl mLocationController;
     private TestableLooper mTestableLooper;
+    private DeviceConfigProxy mDeviceConfigProxy;
 
     @Mock private AppOpsController mAppOpsController;
     @Mock private UserTracker mUserTracker;
@@ -62,15 +68,17 @@
         MockitoAnnotations.initMocks(this);
         when(mUserTracker.getUserId()).thenReturn(UserHandle.USER_SYSTEM);
         when(mUserTracker.getUserHandle()).thenReturn(UserHandle.SYSTEM);
+        mDeviceConfigProxy = new DeviceConfigProxyFake();
 
         mTestableLooper = TestableLooper.get(this);
-        mLocationController = spy(new LocationControllerImpl(mContext,
+        mLocationController = new LocationControllerImpl(mContext,
                 mAppOpsController,
+                mDeviceConfigProxy,
                 mTestableLooper.getLooper(),
                 new Handler(mTestableLooper.getLooper()),
                 mock(BroadcastDispatcher.class),
                 mock(BootCompleteCache.class),
-                mUserTracker));
+                mUserTracker);
 
         mTestableLooper.processAllMessages();
     }
@@ -86,10 +94,13 @@
         mLocationController.addCallback(callback);
         mLocationController.addCallback(mock(LocationChangeCallback.class));
 
-        doReturn(false).when(mLocationController).areActiveHighPowerLocationRequests();
+        when(mAppOpsController.getActiveAppOps()).thenReturn(ImmutableList.of());
         mLocationController.onActiveStateChanged(AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION, 0,
                 "", false);
-        doReturn(true).when(mLocationController).areActiveHighPowerLocationRequests();
+        when(mAppOpsController.getActiveAppOps())
+                .thenReturn(ImmutableList.of(
+                        new AppOpItem(AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION, 0, "",
+                                System.currentTimeMillis())));
         mLocationController.onActiveStateChanged(AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION, 0,
                 "", true);
 
@@ -135,7 +146,10 @@
 
         verify(callback, times(2)).onLocationSettingsChanged(anyBoolean());
 
-        doReturn(true).when(mLocationController).areActiveHighPowerLocationRequests();
+        when(mAppOpsController.getActiveAppOps())
+                .thenReturn(ImmutableList.of(
+                        new AppOpItem(AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION, 0, "",
+                                System.currentTimeMillis())));
         mLocationController.onActiveStateChanged(AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION, 0,
                 "", true);
 
@@ -145,6 +159,46 @@
     }
 
     @Test
+    public void testCallbackNotified_additionalOps() {
+        LocationChangeCallback callback = mock(LocationChangeCallback.class);
+
+        mLocationController.addCallback(callback);
+
+        mTestableLooper.processAllMessages();
+
+        mLocationController.onReceive(mContext, new Intent(LocationManager.MODE_CHANGED_ACTION));
+
+        mTestableLooper.processAllMessages();
+
+        verify(callback, times(2)).onLocationSettingsChanged(anyBoolean());
+
+        mDeviceConfigProxy.setProperty(
+                DeviceConfig.NAMESPACE_PRIVACY,
+                SystemUiDeviceConfigFlags.PROPERTY_LOCATION_INDICATORS_SMALL_ENABLED,
+                "true",
+                true);
+        mTestableLooper.processAllMessages();
+
+        when(mAppOpsController.getActiveAppOps())
+                .thenReturn(ImmutableList.of(
+                        new AppOpItem(AppOpsManager.OP_FINE_LOCATION, 0, "",
+                                System.currentTimeMillis())));
+        mLocationController.onActiveStateChanged(AppOpsManager.OP_FINE_LOCATION, 0,
+                "", true);
+
+        mTestableLooper.processAllMessages();
+
+        verify(callback, times(1)).onLocationActiveChanged(true);
+
+        when(mAppOpsController.getActiveAppOps()).thenReturn(ImmutableList.of());
+        mLocationController.onActiveStateChanged(AppOpsManager.OP_FINE_LOCATION, 0,
+                "", false);
+        mTestableLooper.processAllMessages();
+
+        verify(callback, times(1)).onLocationActiveChanged(false);
+    }
+
+    @Test
     public void testCallbackRemoved() {
         LocationChangeCallback callback = mock(LocationChangeCallback.class);
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/window/StatusBarWindowStateControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/window/StatusBarWindowStateControllerTest.kt
new file mode 100644
index 0000000..8576d4f
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/window/StatusBarWindowStateControllerTest.kt
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.window
+
+import android.app.StatusBarManager.WindowVisibleState
+import android.app.StatusBarManager.WINDOW_NAVIGATION_BAR
+import android.app.StatusBarManager.WINDOW_STATE_HIDDEN
+import android.app.StatusBarManager.WINDOW_STATE_SHOWING
+import android.app.StatusBarManager.WINDOW_STATUS_BAR
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.CommandQueue
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.mockito.ArgumentCaptor
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+class StatusBarWindowStateControllerTest : SysuiTestCase() {
+    private lateinit var controller: StatusBarWindowStateController
+    private lateinit var callback: CommandQueue.Callbacks
+
+    @Mock
+    private lateinit var commandQueue: CommandQueue
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+        controller = StatusBarWindowStateController(DISPLAY_ID, commandQueue)
+
+        val callbackCaptor = ArgumentCaptor.forClass(CommandQueue.Callbacks::class.java)
+        verify(commandQueue).addCallback(callbackCaptor.capture())
+        callback = callbackCaptor.value!!
+    }
+
+    @Test
+    fun setWindowState_notSameDisplayId_listenersNotNotified() {
+        val listener = TestListener()
+        controller.addListener(listener)
+
+        callback.setWindowState(DISPLAY_ID + 1, WINDOW_STATUS_BAR, WINDOW_STATE_HIDDEN)
+
+        assertThat(listener.state).isNull()
+    }
+
+    @Test
+    fun setWindowState_notStatusBarWindow_listenersNotNotified() {
+        val listener = TestListener()
+        controller.addListener(listener)
+
+        callback.setWindowState(DISPLAY_ID, WINDOW_NAVIGATION_BAR, WINDOW_STATE_HIDDEN)
+
+        assertThat(listener.state).isNull()
+    }
+
+    @Test
+    fun setWindowState_sameState_listenersNotNotified() {
+        val listener = TestListener()
+        controller.addListener(listener)
+
+        callback.setWindowState(DISPLAY_ID, WINDOW_STATUS_BAR, WINDOW_STATE_SHOWING)
+
+        assertThat(listener.state).isNull()
+    }
+
+    @Test
+    fun setWindowState_newState_listenersNotified() {
+        val listener = TestListener()
+        controller.addListener(listener)
+        val newState = WINDOW_STATE_HIDDEN
+
+        callback.setWindowState(DISPLAY_ID, WINDOW_STATUS_BAR, newState)
+
+        assertThat(listener.state).isEqualTo(newState)
+    }
+
+    private class TestListener : StatusBarWindowStateListener {
+        @WindowVisibleState var state: Int? = null
+        override fun onStatusBarWindowStateChanged(@WindowVisibleState state: Int) {
+            this.state = state
+        }
+    }
+}
+
+private const val DISPLAY_ID = 10
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt
index 46e0b12..f43dc6c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt
@@ -30,6 +30,7 @@
 import com.android.systemui.unfold.util.FoldableTestUtils
 import com.android.systemui.util.mockito.any
 import com.google.common.truth.Truth.assertThat
+import java.lang.Exception
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -39,32 +40,24 @@
 import org.mockito.Mockito.verify
 import org.mockito.Mockito.`when` as whenever
 import org.mockito.MockitoAnnotations
-import java.lang.Exception
 
 @RunWith(AndroidTestingRunner::class)
 @SmallTest
 class DeviceFoldStateProviderTest : SysuiTestCase() {
 
-    @Mock
-    private lateinit var hingeAngleProvider: HingeAngleProvider
+    @Mock private lateinit var hingeAngleProvider: HingeAngleProvider
 
-    @Mock
-    private lateinit var screenStatusProvider: ScreenStatusProvider
+    @Mock private lateinit var screenStatusProvider: ScreenStatusProvider
 
-    @Mock
-    private lateinit var deviceStateManager: DeviceStateManager
+    @Mock private lateinit var deviceStateManager: DeviceStateManager
 
-    @Mock
-    private lateinit var handler: Handler
+    @Mock private lateinit var handler: Handler
 
-    @Captor
-    private lateinit var foldStateListenerCaptor: ArgumentCaptor<FoldStateListener>
+    @Captor private lateinit var foldStateListenerCaptor: ArgumentCaptor<FoldStateListener>
 
-    @Captor
-    private lateinit var screenOnListenerCaptor: ArgumentCaptor<ScreenListener>
+    @Captor private lateinit var screenOnListenerCaptor: ArgumentCaptor<ScreenListener>
 
-    @Captor
-    private lateinit var hingeAngleCaptor: ArgumentCaptor<Consumer<Float>>
+    @Captor private lateinit var hingeAngleCaptor: ArgumentCaptor<Consumer<Float>>
 
     private lateinit var foldStateProvider: DeviceFoldStateProvider
 
@@ -81,24 +74,25 @@
         MockitoAnnotations.initMocks(this)
         deviceStates = FoldableTestUtils.findDeviceStates(context)
 
-        foldStateProvider = DeviceFoldStateProvider(
-            context,
-            hingeAngleProvider,
-            screenStatusProvider,
-            deviceStateManager,
-            context.mainExecutor,
-            handler
-        )
+        foldStateProvider =
+            DeviceFoldStateProvider(
+                context,
+                hingeAngleProvider,
+                screenStatusProvider,
+                deviceStateManager,
+                context.mainExecutor,
+                handler)
 
-        foldStateProvider.addCallback(object : FoldStateProvider.FoldUpdatesListener {
-            override fun onHingeAngleUpdate(angle: Float) {
-                hingeAngleUpdates.add(angle)
-            }
+        foldStateProvider.addCallback(
+            object : FoldStateProvider.FoldUpdatesListener {
+                override fun onHingeAngleUpdate(angle: Float) {
+                    hingeAngleUpdates.add(angle)
+                }
 
-            override fun onFoldUpdate(update: Int) {
-                foldUpdates.add(update)
-            }
-        })
+                override fun onFoldUpdate(update: Int) {
+                    foldUpdates.add(update)
+                }
+            })
         foldStateProvider.start()
 
         verify(deviceStateManager).registerCallback(any(), foldStateListenerCaptor.capture())
@@ -200,9 +194,10 @@
         sendHingeAngleEvent(90)
         sendHingeAngleEvent(80)
 
-        simulateTimeout(ABORT_CLOSING_MILLIS)
+        simulateTimeout(HALF_OPENED_TIMEOUT_MILLIS)
 
-        assertThat(foldUpdates).containsExactly(FOLD_UPDATE_START_CLOSING, FOLD_UPDATE_ABORTED)
+        assertThat(foldUpdates)
+            .containsExactly(FOLD_UPDATE_START_CLOSING, FOLD_UPDATE_FINISH_HALF_OPEN)
     }
 
     @Test
@@ -210,7 +205,7 @@
         sendHingeAngleEvent(90)
         sendHingeAngleEvent(80)
 
-        simulateTimeout(ABORT_CLOSING_MILLIS - 1)
+        simulateTimeout(HALF_OPENED_TIMEOUT_MILLIS - 1)
 
         assertThat(foldUpdates).containsExactly(FOLD_UPDATE_START_CLOSING)
     }
@@ -220,7 +215,7 @@
         sendHingeAngleEvent(180)
         sendHingeAngleEvent(90)
 
-        simulateTimeout(ABORT_CLOSING_MILLIS - 1)
+        simulateTimeout(HALF_OPENED_TIMEOUT_MILLIS - 1)
         sendHingeAngleEvent(80)
 
         assertThat(foldUpdates).containsExactly(FOLD_UPDATE_START_CLOSING)
@@ -231,11 +226,13 @@
         sendHingeAngleEvent(180)
         sendHingeAngleEvent(90)
 
-        simulateTimeout(ABORT_CLOSING_MILLIS - 1) // The timeout should not trigger here.
+        // The timeout should not trigger here.
+        simulateTimeout(HALF_OPENED_TIMEOUT_MILLIS - 1)
         sendHingeAngleEvent(80)
-        simulateTimeout(ABORT_CLOSING_MILLIS) // The timeout should trigger here.
+        simulateTimeout(HALF_OPENED_TIMEOUT_MILLIS) // The timeout should trigger here.
 
-        assertThat(foldUpdates).containsExactly(FOLD_UPDATE_START_CLOSING, FOLD_UPDATE_ABORTED)
+        assertThat(foldUpdates)
+            .containsExactly(FOLD_UPDATE_START_CLOSING, FOLD_UPDATE_FINISH_HALF_OPEN)
     }
 
     @Test
@@ -261,7 +258,7 @@
         }
     }
 
-    private fun simulateTimeout(waitTime: Long = ABORT_CLOSING_MILLIS) {
+    private fun simulateTimeout(waitTime: Long = HALF_OPENED_TIMEOUT_MILLIS) {
         val runnableDelay = scheduledRunnableDelay ?: throw Exception("No runnable scheduled.")
         if (waitTime >= runnableDelay) {
             scheduledRunnable?.run()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeRotationLockController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeRotationLockController.java
index be11024..4f9cb35 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeRotationLockController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeRotationLockController.java
@@ -51,6 +51,11 @@
     }
 
     @Override
+    public boolean isCameraRotationEnabled() {
+        return false;
+    }
+
+    @Override
     public void setRotationLockedAtAngle(boolean locked, int rotation) {
 
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wallet/ui/WalletScreenControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/wallet/ui/WalletScreenControllerTest.java
index e3b07b3..01769e5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wallet/ui/WalletScreenControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wallet/ui/WalletScreenControllerTest.java
@@ -21,7 +21,6 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -96,7 +95,7 @@
     @Mock
     UiEventLogger mUiEventLogger;
     @Captor
-    ArgumentCaptor<Intent> mIntentCaptor;
+    ArgumentCaptor<PendingIntent> mIntentCaptor;
     @Captor
     ArgumentCaptor<QuickAccessWalletClient.OnWalletCardsRetrievedCallback> mCallbackCaptor;
     private WalletScreenController mController;
@@ -374,10 +373,12 @@
 
         mController.onCardClicked(walletCardViewInfo);
 
-        verify(mActivityStarter).startActivity(mIntentCaptor.capture(), eq(true));
+        verify(mActivityStarter).startPendingIntentDismissingKeyguard(mIntentCaptor.capture());
 
-        assertEquals(mWalletIntent.getAction(), mIntentCaptor.getValue().getAction());
-        assertEquals(mWalletIntent.getComponent(), mIntentCaptor.getValue().getComponent());
+        Intent actualIntent = mIntentCaptor.getValue().getIntent();
+
+        assertEquals(mWalletIntent.getAction(), actualIntent.getAction());
+        assertEquals(mWalletIntent.getComponent(), actualIntent.getComponent());
 
         verify(mUiEventLogger, times(1)).log(WalletUiEvent.QAW_CLICK_CARD);
     }
diff --git a/services/Android.bp b/services/Android.bp
index c830c22..74d7f65 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -224,19 +224,13 @@
     },
     dists: [
         {
-            targets: [
-                "sdk",
-                "win_sdk",
-            ],
+            targets: ["sdk"],
             dir: "apistubs/android/system-server/api",
             dest: "android-non-updatable.txt",
             tag: ".api.txt",
         },
         {
-            targets: [
-                "sdk",
-                "win_sdk",
-            ],
+            targets: ["sdk"],
             dir: "apistubs/android/system-server/api",
             dest: "android-non-updatable-removed.txt",
             tag: ".removed-api.txt",
diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
index f050b66..ad3e1d5 100644
--- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
@@ -2033,6 +2033,22 @@
     }
 
     @Override
+    public void setCacheEnabled(boolean enabled) {
+        if (svcConnTracingEnabled()) {
+            logTraceSvcConn("setCacheEnabled", "enabled=" + enabled);
+        }
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            synchronized (mLock) {
+                mUsesAccessibilityCache = enabled;
+                mSystemSupport.onClientChangeLocked(true);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    @Override
     public void logTrace(long timestamp, String where, long loggingTypes, String callingParams,
             int processId, long threadId, int callingUid, Bundle callingStack) {
         if (mTrace.isA11yTracingEnabledForTypes(loggingTypes)) {
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 52a6dc1..e59a3d6 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -193,6 +193,8 @@
 
     private static final int OWN_PROCESS_ID = android.os.Process.myPid();
 
+    public static final int INVALID_SERVICE_ID = -1;
+
     // Each service has an ID. Also provide one for magnification gesture handling
     public static final int MAGNIFICATION_GESTURE_HANDLER_ID = 0;
 
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java
index 38615fe..72bc850 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java
@@ -19,6 +19,8 @@
 import static android.accessibilityservice.AccessibilityTrace.FLAGS_WINDOW_MANAGER_INTERNAL;
 import static android.view.accessibility.MagnificationAnimationCallback.STUB_ANIMATION_CALLBACK;
 
+import static com.android.server.accessibility.AccessibilityManagerService.INVALID_SERVICE_ID;
+
 import android.animation.Animator;
 import android.animation.ValueAnimator;
 import android.annotation.NonNull;
@@ -117,8 +119,7 @@
 
         private final int mDisplayId;
 
-        private static final int INVALID_ID = -1;
-        private int mIdOfLastServiceToMagnify = INVALID_ID;
+        private int mIdOfLastServiceToMagnify = INVALID_SERVICE_ID;
         private boolean mMagnificationActivated = false;
 
         DisplayMagnification(int displayId) {
@@ -425,7 +426,7 @@
                 }
 
                 final float scale = getScale();
-                offsetMagnifiedRegion(scrollX * scale, scrollY * scale, INVALID_ID);
+                offsetMagnifiedRegion(scrollX * scale, scrollY * scale, INVALID_SERVICE_ID);
             }
         }
 
@@ -472,7 +473,7 @@
                 spec.clear();
                 onMagnificationChangedLocked();
             }
-            mIdOfLastServiceToMagnify = INVALID_ID;
+            mIdOfLastServiceToMagnify = INVALID_SERVICE_ID;
             mForceShowMagnifiableBounds = false;
             sendSpecToAnimation(spec, animationCallback);
             return changed;
@@ -519,7 +520,7 @@
             }
             final boolean changed = updateMagnificationSpecLocked(scale, centerX, centerY);
             sendSpecToAnimation(mCurrentMagnificationSpec, animationCallback);
-            if (isMagnifying() && (id != INVALID_ID)) {
+            if (isMagnifying() && (id != INVALID_SERVICE_ID)) {
                 mIdOfLastServiceToMagnify = id;
                 mMagnificationInfoChangedCallback.onRequestMagnificationSpec(mDisplayId,
                         mIdOfLastServiceToMagnify);
@@ -583,7 +584,7 @@
             if (updateCurrentSpecWithOffsetsLocked(nonNormOffsetX, nonNormOffsetY)) {
                 onMagnificationChangedLocked();
             }
-            if (id != INVALID_ID) {
+            if (id != INVALID_SERVICE_ID) {
                 mIdOfLastServiceToMagnify = id;
             }
             sendSpecToAnimation(mCurrentMagnificationSpec, null);
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
index 791da69..037dc1f 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
@@ -22,6 +22,8 @@
 import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW;
 import static android.view.accessibility.MagnificationAnimationCallback.STUB_ANIMATION_CALLBACK;
 
+import static com.android.server.accessibility.AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID;
+
 import android.accessibilityservice.MagnificationConfig;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -240,9 +242,10 @@
      * @param config The targeting magnification config
      * @param animate    {@code true} to animate the transition, {@code false}
      *                   to transition immediately
+     * @param id        The ID of the service requesting the change
      */
     public void transitionMagnificationConfigMode(int displayId, MagnificationConfig config,
-            boolean animate) {
+            boolean animate, int id) {
         synchronized (mLock) {
             final int targetMode = config.getMode();
             final PointF currentBoundsCenter = getCurrentMagnificationBoundsCenterLocked(displayId,
@@ -273,7 +276,7 @@
                 screenMagnificationController.reset(displayId, false);
                 windowMagnificationMgr.enableWindowMagnification(displayId,
                         scale, magnificationCenter.x, magnificationCenter.y,
-                        animate ? STUB_ANIMATION_CALLBACK : null);
+                        animate ? STUB_ANIMATION_CALLBACK : null, id);
             } else if (targetMode == ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN) {
                 windowMagnificationMgr.disableWindowMagnification(displayId, false, null);
                 if (!screenMagnificationController.isRegistered(displayId)) {
@@ -281,7 +284,7 @@
                 }
                 screenMagnificationController.setScaleAndCenter(displayId, scale,
                         magnificationCenter.x, magnificationCenter.y, animate,
-                        AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
+                        id);
             }
         }
     }
@@ -337,7 +340,7 @@
     public void onRequestMagnificationSpec(int displayId, int serviceId) {
         final WindowMagnificationManager windowMagnificationManager;
         synchronized (mLock) {
-            if (serviceId == AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID) {
+            if (serviceId == MAGNIFICATION_GESTURE_HANDLER_ID) {
                 return;
             }
             updateMagnificationButton(displayId, ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
@@ -575,7 +578,7 @@
         synchronized (mLock) {
             if (mWindowMagnificationMgr == null) {
                 mWindowMagnificationMgr = new WindowMagnificationManager(mContext,
-                        mUserId, this, mAms.getTraceManager(),
+                        mLock, this, mAms.getTraceManager(),
                         mScaleProvider);
             }
             return mWindowMagnificationMgr;
@@ -718,11 +721,12 @@
                 }
                 fullScreenMagnificationController.setScaleAndCenter(mDisplayId, mCurrentScale,
                         mCurrentCenter.x, mCurrentCenter.y, mAnimate,
-                        AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
+                        MAGNIFICATION_GESTURE_HANDLER_ID);
             } else {
                 getWindowMagnificationMgr().enableWindowMagnification(mDisplayId,
                         mCurrentScale, mCurrentCenter.x,
-                        mCurrentCenter.y, mAnimate ? STUB_ANIMATION_CALLBACK : null);
+                        mCurrentCenter.y, mAnimate ? STUB_ANIMATION_CALLBACK : null,
+                        MAGNIFICATION_GESTURE_HANDLER_ID);
             }
         }
     }
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationProcessor.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationProcessor.java
index 7a525ee..40f77b0 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationProcessor.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationProcessor.java
@@ -99,7 +99,7 @@
      */
     public boolean setMagnificationConfig(int displayId, @NonNull MagnificationConfig config,
             boolean animate, int id) {
-        if (transitionModeIfNeeded(displayId, config, animate)) {
+        if (transitionModeIfNeeded(displayId, config, animate, id)) {
             return true;
         }
 
@@ -114,7 +114,8 @@
         } else if (configMode == MAGNIFICATION_MODE_WINDOW) {
             return mController.getWindowMagnificationMgr().enableWindowMagnification(displayId,
                     config.getScale(), config.getCenterX(), config.getCenterY(),
-                    animate ? STUB_ANIMATION_CALLBACK : null);
+                    animate ? STUB_ANIMATION_CALLBACK : null,
+                    id);
         }
         return false;
     }
@@ -136,13 +137,13 @@
      * mode when the controlling mode is unchanged or the controlling magnifier is not activated.
      */
     private boolean transitionModeIfNeeded(int displayId, MagnificationConfig config,
-            boolean animate) {
+            boolean animate, int id) {
         int currentMode = getControllingMode(displayId);
         if (currentMode == config.getMode()
                 || !mController.hasDisableMagnificationCallback(displayId)) {
             return false;
         }
-        mController.transitionMagnificationConfigMode(displayId, config, animate);
+        mController.transitionMagnificationConfigMode(displayId, config, animate, id);
         return true;
     }
 
@@ -237,7 +238,8 @@
         if (mode == MAGNIFICATION_MODE_FULLSCREEN) {
             return mController.getFullScreenMagnificationController().reset(displayId, animate);
         } else if (mode == MAGNIFICATION_MODE_WINDOW) {
-            return mController.getWindowMagnificationMgr().reset(displayId);
+            return mController.getWindowMagnificationMgr().disableWindowMagnification(displayId,
+                    false, animate ? STUB_ANIMATION_CALLBACK : null);
         }
         return false;
     }
@@ -256,11 +258,15 @@
     }
 
     /**
-     * {@link FullScreenMagnificationController#resetIfNeeded(int, boolean)}
+     * Resets all the magnifiers on all the displays.
+     * Called when the a11y service connection that has changed the current magnification spec is
+     * unbound or the binder died.
+     *
+     * @param connectionId The connection id
      */
-    // TODO: support window magnification
     public void resetAllIfNeeded(int connectionId) {
         mController.getFullScreenMagnificationController().resetAllIfNeeded(connectionId);
+        mController.getWindowMagnificationMgr().resetAllIfNeeded(connectionId);
     }
 
     /**
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
index 3f6ff25..c4a577d 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
@@ -20,6 +20,9 @@
 import static android.accessibilityservice.AccessibilityTrace.FLAGS_WINDOW_MAGNIFICATION_CONNECTION_CALLBACK;
 import static android.view.accessibility.MagnificationAnimationCallback.STUB_ANIMATION_CALLBACK;
 
+import static com.android.server.accessibility.AccessibilityManagerService.INVALID_SERVICE_ID;
+import static com.android.server.accessibility.AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID;
+
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -84,7 +87,7 @@
     })
     public @interface WindowPosition {}
 
-    private final Object mLock = new Object();
+    private final Object mLock;
     private final Context mContext;
     @VisibleForTesting
     @GuardedBy("mLock")
@@ -149,9 +152,10 @@
     private final AccessibilityTraceManager mTrace;
     private final MagnificationScaleProvider mScaleProvider;
 
-    public WindowMagnificationManager(Context context, int userId, @NonNull Callback callback,
+    public WindowMagnificationManager(Context context, Object lock, @NonNull Callback callback,
             AccessibilityTraceManager trace, MagnificationScaleProvider scaleProvider) {
         mContext = context;
+        mLock = lock;
         mCallback = callback;
         mTrace = trace;
         mScaleProvider = scaleProvider;
@@ -253,7 +257,26 @@
             }
             mWindowMagnifiers.clear();
         }
+    }
 
+    /**
+     * Resets the window magnifier on all displays that had been controlled by the
+     * specified service connection. Called when the service connection is unbound
+     * or binder died.
+     *
+     * @param connectionId The connection id
+     */
+    public void resetAllIfNeeded(int connectionId) {
+        synchronized (mLock) {
+            for (int i = 0; i < mWindowMagnifiers.size(); i++) {
+                final WindowMagnifier magnifier = mWindowMagnifiers.valueAt(i);
+                if (magnifier != null
+                        && magnifier.mEnabled
+                        && connectionId == magnifier.getIdOfLastServiceToControl()) {
+                    magnifier.disableWindowMagnificationInternal(null);
+                }
+            }
+        }
     }
 
     private void resetWindowMagnifiers() {
@@ -310,7 +333,7 @@
     public boolean enableWindowMagnification(int displayId, float scale, float centerX,
             float centerY) {
         return enableWindowMagnification(displayId, scale, centerX, centerY,
-                STUB_ANIMATION_CALLBACK);
+                STUB_ANIMATION_CALLBACK, MAGNIFICATION_GESTURE_HANDLER_ID);
     }
 
     /**
@@ -324,12 +347,13 @@
      * @param centerY The screen-relative Y coordinate around which to center for magnification,
      *                or {@link Float#NaN} to leave unchanged.
      * @param animationCallback Called when the animation result is valid.
+     * @param id The connection ID
      * @return {@code true} if the magnification is enabled successfully.
      */
     public boolean enableWindowMagnification(int displayId, float scale, float centerX,
-            float centerY, @Nullable MagnificationAnimationCallback animationCallback) {
+            float centerY, @Nullable MagnificationAnimationCallback animationCallback, int id) {
         return enableWindowMagnification(displayId, scale, centerX, centerY, animationCallback,
-                WINDOW_POSITION_AT_CENTER);
+                WINDOW_POSITION_AT_CENTER, id);
     }
 
     /**
@@ -348,7 +372,7 @@
     public boolean enableWindowMagnification(int displayId, float scale, float centerX,
             float centerY, @WindowPosition int windowPosition) {
         return enableWindowMagnification(displayId, scale, centerX, centerY,
-                STUB_ANIMATION_CALLBACK, windowPosition);
+                STUB_ANIMATION_CALLBACK, windowPosition, MAGNIFICATION_GESTURE_HANDLER_ID);
     }
 
     /**
@@ -367,7 +391,7 @@
      */
     public boolean enableWindowMagnification(int displayId, float scale, float centerX,
             float centerY, @Nullable MagnificationAnimationCallback animationCallback,
-            @WindowPosition int windowPosition) {
+            @WindowPosition int windowPosition, int id) {
         final boolean enabled;
         boolean previousEnabled;
         synchronized (mLock) {
@@ -380,7 +404,7 @@
             }
             previousEnabled = magnifier.mEnabled;
             enabled = magnifier.enableWindowMagnificationInternal(scale, centerX, centerY,
-                    animationCallback, windowPosition);
+                    animationCallback, windowPosition, id);
         }
 
         if (enabled && !previousEnabled) {
@@ -394,9 +418,10 @@
      *
      * @param displayId The logical display id.
      * @param clear {@true} Clears the state of window magnification.
+     * @return {@code true} if the magnification is turned to be disabled successfully
      */
-    void disableWindowMagnification(int displayId, boolean clear) {
-        disableWindowMagnification(displayId, clear, STUB_ANIMATION_CALLBACK);
+    boolean disableWindowMagnification(int displayId, boolean clear) {
+        return disableWindowMagnification(displayId, clear, STUB_ANIMATION_CALLBACK);
     }
 
     /**
@@ -405,14 +430,15 @@
      * @param displayId The logical display id.
      * @param clear {@true} Clears the state of window magnification.
      * @param animationCallback Called when the animation result is valid.
+     * @return {@code true} if the magnification is turned to be disabled successfully
      */
-    void disableWindowMagnification(int displayId, boolean clear,
+    public boolean disableWindowMagnification(int displayId, boolean clear,
             MagnificationAnimationCallback animationCallback) {
         final boolean disabled;
         synchronized (mLock) {
             WindowMagnifier magnifier = mWindowMagnifiers.get(displayId);
             if (magnifier == null || mConnectionWrapper == null) {
-                return;
+                return false;
             }
             disabled = magnifier.disableWindowMagnificationInternal(animationCallback);
             if (clear) {
@@ -423,6 +449,7 @@
         if (disabled) {
             mCallback.onWindowMagnificationActivationState(displayId, false);
         }
+        return disabled;
     }
 
     /**
@@ -490,7 +517,7 @@
     public float getScale(int displayId) {
         synchronized (mLock) {
             WindowMagnifier magnifier = mWindowMagnifiers.get(displayId);
-            if (magnifier == null) {
+            if (magnifier == null || !magnifier.mEnabled) {
                 return 1.0f;
             }
             return magnifier.getScale();
@@ -548,7 +575,7 @@
     public float getCenterX(int displayId) {
         synchronized (mLock) {
             WindowMagnifier magnifier = mWindowMagnifiers.get(displayId);
-            if (magnifier == null) {
+            if (magnifier == null || !magnifier.mEnabled) {
                 return Float.NaN;
             }
             return magnifier.getCenterX();
@@ -564,7 +591,7 @@
     public float getCenterY(int displayId) {
         synchronized (mLock) {
             WindowMagnifier magnifier = mWindowMagnifiers.get(displayId);
-            if (magnifier == null) {
+            if (magnifier == null || !magnifier.mEnabled) {
                 return Float.NaN;
             }
             return magnifier.getCenterY();
@@ -581,7 +608,7 @@
     public void getMagnificationSourceBounds(int displayId, @NonNull Region outRegion) {
         synchronized (mLock) {
             WindowMagnifier magnifier = mWindowMagnifiers.get(displayId);
-            if (magnifier == null) {
+            if (magnifier == null || !magnifier.mEnabled) {
                 outRegion.setEmpty();
             } else {
                 outRegion.set(magnifier.mSourceBounds);
@@ -590,24 +617,6 @@
     }
 
     /**
-     * Resets the magnification scale and center.
-     *
-     * @param displayId The logical display id.
-     * @return {@code true} if the magnification spec changed, {@code false} if
-     * the spec did not change
-     */
-    public boolean reset(int displayId) {
-        synchronized (mLock) {
-            WindowMagnifier magnifier = mWindowMagnifiers.get(displayId);
-            if (magnifier == null) {
-                return false;
-            }
-            magnifier.reset();
-            return true;
-        }
-    }
-
-    /**
      * Creates the windowMagnifier based on the specified display and stores it.
      *
      * @param displayId logical display id.
@@ -722,6 +731,9 @@
     /**
      * A class manipulates window magnification per display and contains the magnification
      * information.
+     * <p>
+     * This class requires to hold the lock when controlling the magnifier.
+     * </p>
      */
     private static class WindowMagnifier {
 
@@ -735,6 +747,8 @@
         // The magnified bounds on the screen.
         private final Rect mSourceBounds = new Rect();
 
+        private int mIdOfLastServiceToControl = INVALID_SERVICE_ID;
+
         private PointF mMagnificationFrameOffsetRatio = new PointF(0f, 0f);
 
         WindowMagnifier(int displayId, WindowMagnificationManager windowMagnificationManager) {
@@ -745,7 +759,7 @@
         @GuardedBy("mLock")
         boolean enableWindowMagnificationInternal(float scale, float centerX, float centerY,
                 @Nullable MagnificationAnimationCallback animationCallback,
-                @WindowPosition int windowPosition) {
+                @WindowPosition int windowPosition, int id) {
             // Handle defaults. The scale may be NAN when just updating magnification center.
             if (Float.isNaN(scale)) {
                 scale = getScale();
@@ -757,7 +771,7 @@
                     mMagnificationFrameOffsetRatio.y, animationCallback)) {
                 mScale = normScale;
                 mEnabled = true;
-
+                mIdOfLastServiceToControl = id;
                 return true;
             }
             return false;
@@ -785,7 +799,7 @@
             if (mWindowMagnificationManager.disableWindowMagnificationInternal(
                     mDisplayId, animationResultCallback)) {
                 mEnabled = false;
-
+                mIdOfLastServiceToControl = INVALID_SERVICE_ID;
                 return true;
             }
             return false;
@@ -813,6 +827,13 @@
             mBounds.set(rect);
         }
 
+        /**
+         * Returns the ID of the last service that changed the magnification config.
+         */
+        int getIdOfLastServiceToControl() {
+            return mIdOfLastServiceToControl;
+        }
+
         @GuardedBy("mLock")
         int pointersInWindow(MotionEvent motionEvent) {
             int count = 0;
@@ -840,6 +861,8 @@
         @GuardedBy("mLock")
         void reset() {
             mEnabled = false;
+            mIdOfLastServiceToControl = INVALID_SERVICE_ID;
+            mSourceBounds.setEmpty();
         }
 
         @GuardedBy("mLock")
@@ -849,12 +872,12 @@
 
         @GuardedBy("mLock")
         float getCenterX() {
-            return mEnabled ? mSourceBounds.exactCenterX() : Float.NaN;
+            return mSourceBounds.exactCenterX();
         }
 
         @GuardedBy("mLock")
         float getCenterY() {
-            return mEnabled ? mSourceBounds.exactCenterY() : Float.NaN;
+            return mSourceBounds.exactCenterY();
         }
     }
 
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 422749e..051281c 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -241,9 +241,6 @@
     protected void registerForExtraSettingsChanges(@NonNull ContentResolver resolver,
             @NonNull ContentObserver observer) {
         resolver.registerContentObserver(Settings.Global.getUriFor(
-                Settings.Global.AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES), false, observer,
-                UserHandle.USER_ALL);
-        resolver.registerContentObserver(Settings.Global.getUriFor(
                 Settings.Global.AUTOFILL_LOGGING_LEVEL), false, observer,
                 UserHandle.USER_ALL);
         resolver.registerContentObserver(Settings.Global.getUriFor(
@@ -274,8 +271,6 @@
                 break;
             default:
                 Slog.w(TAG, "Unexpected property (" + property + "); updating cache instead");
-                // fall through
-            case Settings.Global.AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES:
                 synchronized (mLock) {
                     updateCachedServiceLocked(userId);
                 }
@@ -307,6 +302,9 @@
                 case AutofillManager.DEVICE_CONFIG_AUGMENTED_SERVICE_REQUEST_TIMEOUT:
                     setDeviceConfigProperties();
                     break;
+                case AutofillManager.DEVICE_CONFIG_AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES:
+                    updateCachedServices();
+                    break;
                 default:
                     Slog.i(mTag, "Ignoring change on " + key);
             }
@@ -588,6 +586,15 @@
         }
     }
 
+    private void updateCachedServices() {
+        List<UserInfo> supportedUsers = getSupportedUsers();
+        for (UserInfo userInfo : supportedUsers) {
+            synchronized (mLock) {
+                updateCachedServiceLocked(userInfo.id);
+            }
+        }
+    }
+
     // Called by Shell command.
     void calculateScore(@Nullable String algorithmName, @NonNull String value1,
             @NonNull String value2, @NonNull RemoteCallback callback) {
@@ -702,31 +709,44 @@
             return;
         }
 
-        final Map<String, String[]> whiteListedPackages = getWhitelistedCompatModePackages();
+        final Map<String, String[]> allowedPackages = getAllowedCompatModePackages();
         final int compatPackageCount = compatPackages.size();
         for (int i = 0; i < compatPackageCount; i++) {
             final String packageName = compatPackages.keyAt(i);
-            if (whiteListedPackages == null || !whiteListedPackages.containsKey(packageName)) {
-                Slog.w(TAG, "Ignoring not whitelisted compat package " + packageName);
+            if (allowedPackages == null || !allowedPackages.containsKey(packageName)) {
+                Slog.w(TAG, "Ignoring not allowed compat package " + packageName);
                 continue;
             }
             final Long maxVersionCode = compatPackages.valueAt(i);
             if (maxVersionCode != null) {
                 mAutofillCompatState.addCompatibilityModeRequest(packageName,
-                        maxVersionCode, whiteListedPackages.get(packageName), userId);
+                        maxVersionCode, allowedPackages.get(packageName), userId);
             }
         }
     }
 
-    private String getWhitelistedCompatModePackagesFromSettings() {
+    private String getAllowedCompatModePackagesFromDeviceConfig() {
+        String config = DeviceConfig.getString(
+                DeviceConfig.NAMESPACE_AUTOFILL,
+                AutofillManager.DEVICE_CONFIG_AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES,
+                /* defaultValue */ null);
+        if (!TextUtils.isEmpty(config)) {
+            return config;
+        }
+        // Fallback to Settings.Global.AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES if
+        // the device config is null.
+        return getAllowedCompatModePackagesFromSettings();
+    }
+
+    private String getAllowedCompatModePackagesFromSettings() {
         return Settings.Global.getString(
                 getContext().getContentResolver(),
                 Settings.Global.AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES);
     }
 
     @Nullable
-    private Map<String, String[]> getWhitelistedCompatModePackages() {
-        return getWhitelistedCompatModePackages(getWhitelistedCompatModePackagesFromSettings());
+    private Map<String, String[]> getAllowedCompatModePackages() {
+        return getAllowedCompatModePackages(getAllowedCompatModePackagesFromDeviceConfig());
     }
 
     private void send(@NonNull IResultReceiver receiver, int value) {
@@ -771,7 +791,7 @@
 
     @Nullable
     @VisibleForTesting
-    static Map<String, String[]> getWhitelistedCompatModePackages(String setting) {
+    static Map<String, String[]> getAllowedCompatModePackages(String setting) {
         if (TextUtils.isEmpty(setting)) {
             return null;
         }
@@ -1756,8 +1776,8 @@
                     mUi.dump(pw);
                     pw.print("Autofill Compat State: ");
                     mAutofillCompatState.dump(prefix, pw);
-                    pw.print("from settings: ");
-                    pw.println(getWhitelistedCompatModePackagesFromSettings());
+                    pw.print("from device config: ");
+                    pw.println(getAllowedCompatModePackagesFromDeviceConfig());
                     if (mSupportedSmartSuggestionModes != 0) {
                         pw.print("Smart Suggestion modes: ");
                         pw.println(getSmartSuggestionModeToString(mSupportedSmartSuggestionModes));
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
index f8da035..efa026b 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
@@ -3907,14 +3907,20 @@
         }
 
         int operationType;
+        TransportConnection transportConnection = null;
         try {
-            operationType = getOperationTypeFromTransport(
-                    mTransportManager.getTransportClientOrThrow(transport, /* caller */
-                            "BMS.beginRestoreSession"));
+            transportConnection = mTransportManager.getTransportClientOrThrow(
+                    transport, /* caller */"BMS.beginRestoreSession");
+            operationType = getOperationTypeFromTransport(transportConnection);
         } catch (TransportNotAvailableException | TransportNotRegisteredException
                 | RemoteException e) {
             Slog.w(TAG, "Failed to get operation type from transport: " + e);
             return null;
+        } finally {
+            if (transportConnection != null) {
+                mTransportManager.disposeOfTransportClient(transportConnection,
+                        /* caller */"BMS.beginRestoreSession");
+            }
         }
 
         synchronized (this) {
diff --git a/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java b/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java
index 637994f..1914164 100644
--- a/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java
+++ b/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java
@@ -22,7 +22,6 @@
 import static android.companion.CompanionDeviceManager.COMPANION_DEVICE_DISCOVERY_PACKAGE_NAME;
 import static android.content.ComponentName.createRelative;
 
-import static com.android.internal.util.CollectionUtils.filter;
 import static com.android.server.companion.CompanionDeviceManagerService.DEBUG;
 import static com.android.server.companion.CompanionDeviceManagerService.LOG_TAG;
 import static com.android.server.companion.PermissionsUtils.enforcePermissionsForAssociation;
@@ -57,6 +56,7 @@
 
 import java.util.Arrays;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Set;
 
 /**
@@ -124,14 +124,17 @@
     private static final int ASSOCIATE_WITHOUT_PROMPT_MAX_PER_TIME_WINDOW = 5;
     private static final long ASSOCIATE_WITHOUT_PROMPT_WINDOW_MS = 60 * 60 * 1000; // 60 min;
 
-    private final Context mContext;
-    private final CompanionDeviceManagerService mService;
-    private final PackageManagerInternal mPackageManager;
+    private final @NonNull Context mContext;
+    private final @NonNull CompanionDeviceManagerService mService;
+    private final @NonNull PackageManagerInternal mPackageManager;
+    private final @NonNull AssociationStore mAssociationStore;
 
-    AssociationRequestsProcessor(CompanionDeviceManagerService service) {
+    AssociationRequestsProcessor(@NonNull CompanionDeviceManagerService service,
+            @NonNull AssociationStore associationStore) {
         mContext = service.getContext();
         mService = service;
         mPackageManager = service.mPackageManagerInternal;
+        mAssociationStore = associationStore;
     }
 
     /**
@@ -330,18 +333,24 @@
         }
 
         // Throttle frequent associations
-        long now = System.currentTimeMillis();
-        Set<AssociationInfo> recentAssociations = filter(
-                mService.getAssociations(userId, packageName),
-                a -> now - a.getTimeApprovedMs() < ASSOCIATE_WITHOUT_PROMPT_WINDOW_MS);
-
-        if (recentAssociations.size() >= ASSOCIATE_WITHOUT_PROMPT_MAX_PER_TIME_WINDOW) {
-            Slog.w(TAG, "Too many associations. " + packageName
-                    + " already associated " + recentAssociations.size()
-                    + " devices within the last " + ASSOCIATE_WITHOUT_PROMPT_WINDOW_MS
-                    + "ms: " + recentAssociations);
-            return false;
+        final long now = System.currentTimeMillis();
+        final List<AssociationInfo> associationForPackage =
+                mAssociationStore.getAssociationsForPackage(userId, packageName);
+        // Number of "recent" associations.
+        int recent = 0;
+        for (AssociationInfo association : associationForPackage) {
+            final boolean isRecent =
+                    now - association.getTimeApprovedMs() < ASSOCIATE_WITHOUT_PROMPT_WINDOW_MS;
+            if (isRecent) {
+                if (++recent >= ASSOCIATE_WITHOUT_PROMPT_MAX_PER_TIME_WINDOW) {
+                    Slog.w(TAG, "Too many associations: " + packageName + " already "
+                            + "associated " + recent + " devices within the last "
+                            + ASSOCIATE_WITHOUT_PROMPT_WINDOW_MS + "ms");
+                    return false;
+                }
+            }
         }
+
         String[] sameOemCerts = mContext.getResources()
                 .getStringArray(com.android.internal.R.array.config_companionDeviceCerts);
 
diff --git a/services/companion/java/com/android/server/companion/AssociationStore.java b/services/companion/java/com/android/server/companion/AssociationStore.java
new file mode 100644
index 0000000..58fc8f7
--- /dev/null
+++ b/services/companion/java/com/android/server/companion/AssociationStore.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.companion;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.companion.AssociationInfo;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * Interface for a store of {@link AssociationInfo}-s.
+ */
+public interface AssociationStore {
+
+    @IntDef(prefix = { "CHANGE_TYPE_" }, value = {
+            CHANGE_TYPE_ADDED,
+            CHANGE_TYPE_REMOVED,
+            CHANGE_TYPE_UPDATED_ADDRESS_CHANGED,
+            CHANGE_TYPE_UPDATED_ADDRESS_UNCHANGED,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    @interface ChangeType {}
+
+    int CHANGE_TYPE_ADDED = 0;
+    int CHANGE_TYPE_REMOVED = 1;
+    int CHANGE_TYPE_UPDATED_ADDRESS_CHANGED = 2;
+    int CHANGE_TYPE_UPDATED_ADDRESS_UNCHANGED = 3;
+
+    /**  Listener for any changes to {@link AssociationInfo}-s. */
+    interface OnChangeListener {
+        default void onAssociationChanged(
+                @ChangeType int changeType, AssociationInfo association) {}
+
+        default void onAssociationAdded(AssociationInfo association) {}
+
+        default void onAssociationRemoved(AssociationInfo association) {}
+
+        default void onAssociationUpdated(AssociationInfo association, boolean addressChanged) {}
+    }
+
+    /**
+     * @return all CDM associations.
+     */
+    @NonNull
+    Collection<AssociationInfo> getAssociations();
+
+    /**
+     * @return a {@link List} of associations that belong to the user.
+     */
+    @NonNull
+    List<AssociationInfo> getAssociationsForUser(@UserIdInt int userId);
+
+    /**
+     * @return a {@link List} of association that belong to the package.
+     */
+    @NonNull
+    List<AssociationInfo> getAssociationsForPackage(
+            @UserIdInt int userId, @NonNull String packageName);
+
+    /**
+     * @return an association with the given address that belong to the given package if such an
+     * association exists, otherwise {@code null}.
+     */
+    @Nullable
+    AssociationInfo getAssociationsForPackageWithAddress(
+            @UserIdInt int userId, @NonNull String packageName, @NonNull String macAddress);
+
+    /**
+     * @return an association with the given id if such an association exists, otherwise
+     * {@code null}.
+     */
+    @Nullable
+    AssociationInfo getAssociationById(int id);
+
+    /**
+     * @return all associations with the given MAc address.
+     */
+    @NonNull
+    List<AssociationInfo> getAssociationsByAddress(@NonNull String macAddress);
+
+    /** Register a {@link OnChangeListener} */
+    void registerListener(@NonNull OnChangeListener listener);
+
+    /** Un-register a previously registered {@link OnChangeListener} */
+    void unregisterListener(@NonNull OnChangeListener listener);
+
+    /** @hide */
+    static String changeTypeToString(@ChangeType int changeType) {
+        switch (changeType) {
+            case CHANGE_TYPE_ADDED:
+                return "ASSOCIATION_ADDED";
+
+            case CHANGE_TYPE_REMOVED:
+                return "ASSOCIATION_REMOVED";
+
+            case CHANGE_TYPE_UPDATED_ADDRESS_CHANGED:
+                return "ASSOCIATION_UPDATED";
+
+            case CHANGE_TYPE_UPDATED_ADDRESS_UNCHANGED:
+                return "ASSOCIATION_UPDATED_ADDRESS_UNCHANGED";
+
+            default:
+                return "Unknown (" + changeType + ")";
+        }
+    }
+}
diff --git a/services/companion/java/com/android/server/companion/AssociationStoreImpl.java b/services/companion/java/com/android/server/companion/AssociationStoreImpl.java
new file mode 100644
index 0000000..3f0200e
--- /dev/null
+++ b/services/companion/java/com/android/server/companion/AssociationStoreImpl.java
@@ -0,0 +1,302 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.companion;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.companion.AssociationInfo;
+import android.net.MacAddress;
+import android.util.Log;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.CollectionUtils;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * Implementation of the {@link AssociationStore}, with addition of the methods for modification.
+ * <ul>
+ * <li> {@link #addAssociation(AssociationInfo)}
+ * <li> {@link #removeAssociation(int)}
+ * <li> {@link #updateAssociation(AssociationInfo)}
+ * </ul>
+ *
+ * The class has package-private access level, and instances of the class should only be created by
+ * the {@link CompanionDeviceManagerService}.
+ * Other system component (both inside and outside if the com.android.server.companion package)
+ * should use public {@link AssociationStore} interface.
+ */
+class AssociationStoreImpl implements AssociationStore {
+    private static final boolean DEBUG = false;
+    private static final String TAG = "AssociationStore";
+
+    private final Object mLock = new Object();
+
+    @GuardedBy("mLock")
+    private final Map<Integer, AssociationInfo> mIdMap;
+    @GuardedBy("mLock")
+    private final Map<MacAddress, Set<Integer>> mAddressMap;
+    @GuardedBy("mLock")
+    private final SparseArray<List<AssociationInfo>> mCachedPerUser = new SparseArray<>();
+
+    @GuardedBy("mListeners")
+    private final Set<OnChangeListener> mListeners = new LinkedHashSet<>();
+
+    AssociationStoreImpl(Collection<AssociationInfo> associations) {
+        synchronized (mLock) {
+            final int size = associations.size();
+            mIdMap = new HashMap<>(size);
+            mAddressMap = new HashMap<>(size);
+
+            for (AssociationInfo association : associations) {
+                final int id = association.getId();
+                mIdMap.put(id, association);
+
+                final MacAddress address = association.getDeviceMacAddress();
+                if (address != null) {
+                    mAddressMap.computeIfAbsent(address, it -> new HashSet<>()).add(id);
+                }
+            }
+        }
+    }
+
+    void addAssociation(@NonNull AssociationInfo association) {
+        final int id = association.getId();
+
+        if (DEBUG) {
+            Log.i(TAG, "addAssociation() " + association.toShortString());
+            Log.d(TAG, "  association=" + association);
+        }
+
+        synchronized (mLock) {
+            if (mIdMap.containsKey(id)) {
+                if (DEBUG) Log.w(TAG, "Association already stored.");
+                return;
+            }
+            mIdMap.put(id, association);
+
+            final MacAddress address = association.getDeviceMacAddress();
+            if (address != null) {
+                mAddressMap.computeIfAbsent(address, it -> new HashSet<>()).add(id);
+            }
+
+            invalidateCacheForUserLocked(association.getUserId());
+        }
+
+        broadcastChange(CHANGE_TYPE_ADDED, association);
+    }
+
+    void updateAssociation(@NonNull AssociationInfo updated) {
+        final int id = updated.getId();
+
+        if (DEBUG) {
+            Log.i(TAG, "updateAssociation() " + updated.toShortString());
+            Log.d(TAG, "  updated=" + updated);
+        }
+
+        final AssociationInfo current;
+        final boolean macAddressChanged;
+        synchronized (mLock) {
+            current = mIdMap.get(id);
+            if (current == null) {
+                if (DEBUG) Log.w(TAG, "Association with id " + id + " does not exist.");
+                return;
+            }
+            if (DEBUG) Log.d(TAG, "  current=" + current);
+
+            if (current.equals(updated)) {
+                if (DEBUG) Log.w(TAG, "  No changes.");
+                return;
+            }
+
+            // Update the ID-to-Association map.
+            mIdMap.put(id, updated);
+
+            // Update the MacAddress-to-List<Association> map if needed.
+            final MacAddress updatedAddress = updated.getDeviceMacAddress();
+            final MacAddress currentAddress = current.getDeviceMacAddress();
+            macAddressChanged = Objects.equals(
+                    current.getDeviceMacAddress(), updated.getDeviceMacAddress());
+            if (macAddressChanged) {
+                if (currentAddress != null) {
+                    mAddressMap.get(currentAddress).remove(id);
+                }
+                if (updatedAddress != null) {
+                    mAddressMap.computeIfAbsent(updatedAddress, it -> new HashSet<>()).add(id);
+                }
+            }
+        }
+
+        final int changeType = macAddressChanged ? CHANGE_TYPE_UPDATED_ADDRESS_CHANGED
+                : CHANGE_TYPE_UPDATED_ADDRESS_UNCHANGED;
+        broadcastChange(changeType, updated);
+    }
+
+    void removeAssociation(int id) {
+        if (DEBUG) Log.i(TAG, "removeAssociation() id=" + id);
+
+        final AssociationInfo association;
+        synchronized (mLock) {
+            association = mIdMap.remove(id);
+
+            if (association == null) {
+                if (DEBUG) Log.w(TAG, "Association with id " + id + " is not stored.");
+                return;
+            } else {
+                if (DEBUG) {
+                    Log.i(TAG, "removed " + association.toShortString());
+                    Log.d(TAG, "  association=" + association);
+                }
+            }
+
+            final MacAddress macAddress = association.getDeviceMacAddress();
+            if (macAddress != null) {
+                mAddressMap.get(macAddress).remove(id);
+            }
+
+            invalidateCacheForUserLocked(association.getUserId());
+        }
+
+        broadcastChange(CHANGE_TYPE_REMOVED, association);
+    }
+
+    public @NonNull Collection<AssociationInfo> getAssociations() {
+        final Collection<AssociationInfo> allAssociations;
+        synchronized (mLock) {
+            allAssociations = mIdMap.values();
+        }
+        return Collections.unmodifiableCollection(allAssociations);
+    }
+
+    public @NonNull List<AssociationInfo> getAssociationsForUser(@UserIdInt int userId) {
+        synchronized (mLock) {
+            return getAssociationsForUserLocked(userId);
+        }
+    }
+
+    public @NonNull List<AssociationInfo> getAssociationsForPackage(
+            @UserIdInt int userId, @NonNull String packageName) {
+        final List<AssociationInfo> associationsForUser = getAssociationsForUser(userId);
+        final List<AssociationInfo> associationsForPackage =
+                CollectionUtils.filter(associationsForUser,
+                        it -> it.getPackageName().equals(packageName));
+        return Collections.unmodifiableList(associationsForPackage);
+    }
+
+    public @Nullable AssociationInfo getAssociationsForPackageWithAddress(
+            @UserIdInt int userId, @NonNull String packageName, @NonNull String macAddress) {
+        final List<AssociationInfo> associations = getAssociationsByAddress(macAddress);
+        return CollectionUtils.find(associations,
+                it -> it.belongsToPackage(userId, packageName));
+    }
+
+    public @Nullable AssociationInfo getAssociationById(int id) {
+        synchronized (mLock) {
+            return mIdMap.get(id);
+        }
+    }
+
+    public @NonNull List<AssociationInfo> getAssociationsByAddress(@NonNull String macAddress) {
+        final MacAddress address = MacAddress.fromString(macAddress);
+
+        synchronized (mLock) {
+            final Set<Integer> ids = mAddressMap.get(address);
+            if (ids == null) return Collections.emptyList();
+
+            final List<AssociationInfo> associations = new ArrayList<>();
+            for (AssociationInfo association : mIdMap.values()) {
+                if (address.equals(association.getDeviceMacAddress())) {
+                    associations.add(association);
+                }
+            }
+
+            return Collections.unmodifiableList(associations);
+        }
+    }
+
+    @GuardedBy("mLock")
+    private @NonNull List<AssociationInfo> getAssociationsForUserLocked(@UserIdInt int userId) {
+        final List<AssociationInfo> cached = mCachedPerUser.get(userId);
+        if (cached != null) {
+            return cached;
+        }
+
+        final List<AssociationInfo> associationsForUser = new ArrayList<>();
+        for (AssociationInfo association : mIdMap.values()) {
+            if (association.getUserId() == userId) {
+                associationsForUser.add(association);
+            }
+        }
+        final List<AssociationInfo> set = Collections.unmodifiableList(associationsForUser);
+        mCachedPerUser.set(userId, set);
+        return set;
+    }
+
+    @GuardedBy("mLock")
+    private void invalidateCacheForUserLocked(@UserIdInt int userId) {
+        mCachedPerUser.delete(userId);
+    }
+
+    public void registerListener(@NonNull OnChangeListener listener) {
+        synchronized (mListeners) {
+            mListeners.add(listener);
+        }
+    }
+
+    public void unregisterListener(@NonNull OnChangeListener listener) {
+        synchronized (mListeners) {
+            mListeners.remove(listener);
+        }
+    }
+
+    private void broadcastChange(@ChangeType int changeType, AssociationInfo association) {
+        synchronized (mListeners) {
+            for (OnChangeListener listener : mListeners) {
+                listener.onAssociationChanged(changeType, association);
+
+                switch (changeType) {
+                    case CHANGE_TYPE_ADDED:
+                        listener.onAssociationAdded(association);
+                        break;
+
+                    case CHANGE_TYPE_REMOVED:
+                        listener.onAssociationRemoved(association);
+                        break;
+
+                    case CHANGE_TYPE_UPDATED_ADDRESS_CHANGED:
+                        listener.onAssociationUpdated(association, true);
+                        break;
+
+                    case CHANGE_TYPE_UPDATED_ADDRESS_UNCHANGED:
+                        listener.onAssociationUpdated(association, false);
+                        break;
+                }
+            }
+        }
+    }
+}
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index 626128a..5aa1c93 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -27,15 +27,12 @@
 import static android.os.Process.SYSTEM_UID;
 import static android.os.UserHandle.getCallingUserId;
 
-import static com.android.internal.util.CollectionUtils.add;
 import static com.android.internal.util.CollectionUtils.any;
-import static com.android.internal.util.CollectionUtils.filter;
 import static com.android.internal.util.CollectionUtils.find;
-import static com.android.internal.util.CollectionUtils.forEach;
-import static com.android.internal.util.CollectionUtils.map;
 import static com.android.internal.util.Preconditions.checkState;
 import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
 import static com.android.internal.util.function.pooled.PooledLambda.obtainRunnable;
+import static com.android.server.companion.AssociationStore.CHANGE_TYPE_UPDATED_ADDRESS_UNCHANGED;
 import static com.android.server.companion.PermissionsUtils.checkCallerCanManageAssociationsForPackage;
 import static com.android.server.companion.PermissionsUtils.checkCallerCanManageCompanionDevice;
 import static com.android.server.companion.PermissionsUtils.enforceCallerCanInteractWithUserId;
@@ -45,8 +42,6 @@
 import static com.android.server.companion.RolesUtils.addRoleHolderForAssociation;
 import static com.android.server.companion.RolesUtils.removeRoleHolderForAssociation;
 
-import static java.util.Collections.emptySet;
-import static java.util.Collections.unmodifiableSet;
 import static java.util.Objects.requireNonNull;
 import static java.util.concurrent.TimeUnit.MINUTES;
 
@@ -82,7 +77,6 @@
 import android.content.pm.PackageItemInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
-import android.content.pm.UserInfo;
 import android.net.MacAddress;
 import android.net.NetworkPolicyManager;
 import android.os.Binder;
@@ -90,6 +84,7 @@
 import android.os.Handler;
 import android.os.Parcel;
 import android.os.PowerWhitelistManager;
+import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.ServiceManager;
@@ -111,9 +106,7 @@
 import com.android.internal.notification.NotificationAccessConfirmationActivityContract;
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.CollectionUtils;
 import com.android.internal.util.DumpUtils;
-import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.server.FgThread;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
@@ -126,6 +119,7 @@
 import java.text.DateFormat;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -134,12 +128,11 @@
 import java.util.Objects;
 import java.util.Set;
 import java.util.TimeZone;
-import java.util.function.Function;
-import java.util.function.Predicate;
 
 /** @hide */
 @SuppressLint("LongLogTag")
-public class CompanionDeviceManagerService extends SystemService {
+public class CompanionDeviceManagerService extends SystemService
+        implements AssociationStore.OnChangeListener {
     static final String LOG_TAG = "CompanionDeviceManagerService";
     static final boolean DEBUG = false;
 
@@ -161,10 +154,11 @@
         sDateFormat.setTimeZone(TimeZone.getDefault());
     }
 
-    private final CompanionDeviceManagerImpl mImpl;
     // Persistent data store for all Associations.
-    private final PersistentDataStore mPersistentDataStore;
-    private final AssociationRequestsProcessor mAssociationRequestsProcessor;
+    private PersistentDataStore mPersistentStore;
+    private AssociationStoreImpl mAssociationStore;
+    private AssociationRequestsProcessor mAssociationRequestsProcessor;
+
     private PowerWhitelistManager mPowerWhitelistManager;
     private IAppOpsService mAppOpsManager;
     private BluetoothAdapter mBluetoothAdapter;
@@ -183,21 +177,19 @@
             mUnbindDeviceListenersRunnable = new UnbindDeviceListenersRunnable();
     private ArrayMap<String, TriggerDeviceDisappearedRunnable> mTriggerDeviceDisappearedRunnables =
             new ArrayMap<>();
+    private final RemoteCallbackList<IOnAssociationsChangedListener> mListeners =
+            new RemoteCallbackList<>();
 
-    final Object mLock = new Object();
     final Handler mMainHandler = Handler.getMain();
     private CompanionDevicePresenceController mCompanionDevicePresenceController;
 
-    /** Maps a {@link UserIdInt} to a set of associations for the user. */
-    @GuardedBy("mLock")
-    private final SparseArray<Set<AssociationInfo>> mCachedAssociations = new SparseArray<>();
     /**
      * A structure that consist of two nested maps, and effectively maps (userId + packageName) to
      * a list of IDs that have been previously assigned to associations for that package.
      * We maintain this structure so that we never re-use association IDs for the same package
      * (until it's uninstalled).
      */
-    @GuardedBy("mLock")
+    @GuardedBy("mPreviouslyUsedIds")
     private final SparseArray<Map<String, Set<Integer>>> mPreviouslyUsedIds = new SparseArray<>();
 
     ActivityTaskManagerInternal mAtmInternal;
@@ -206,8 +198,6 @@
 
     public CompanionDeviceManagerService(Context context) {
         super(context);
-        mImpl = new CompanionDeviceManagerImpl();
-        mPersistentDataStore = new PersistentDataStore();
 
         mPowerWhitelistManager = context.getSystemService(PowerWhitelistManager.class);
         mAppOpsManager = IAppOpsService.Stub.asInterface(
@@ -218,49 +208,36 @@
         mPermissionControllerManager = requireNonNull(
                 context.getSystemService(PermissionControllerManager.class));
         mUserManager = context.getSystemService(UserManager.class);
-        mCompanionDevicePresenceController = new CompanionDevicePresenceController(this);
-        mAssociationRequestsProcessor = new AssociationRequestsProcessor(this);
-
-        registerPackageMonitor();
-    }
-
-    private void registerPackageMonitor() {
-        new PackageMonitor() {
-            @Override
-            public void onPackageRemoved(String packageName, int uid) {
-                final int userId = getChangingUserId();
-                Slog.i(LOG_TAG, "onPackageRemoved() u" + userId + "/" + packageName);
-
-                clearAssociationForPackage(userId, packageName);
-            }
-
-            @Override
-            public void onPackageDataCleared(String packageName, int uid) {
-                final int userId = getChangingUserId();
-                Slog.i(LOG_TAG, "onPackageDataCleared() u" + userId + "/" + packageName);
-
-                clearAssociationForPackage(userId, packageName);
-            }
-
-            @Override
-            public void onPackageModified(String packageName) {
-                final int userId = getChangingUserId();
-                Slog.i(LOG_TAG, "onPackageModified() u" + userId + "/" + packageName);
-
-                forEach(getAssociations(userId, packageName), association ->
-                        updateSpecialAccessPermissionForAssociatedPackage(association));
-            }
-        }.register(getContext(), FgThread.get().getLooper(), UserHandle.ALL, true);
     }
 
     @Override
     public void onStart() {
-        publishBinderService(Context.COMPANION_DEVICE_SERVICE, mImpl);
+        mPersistentStore = new PersistentDataStore();
+        final Set<AssociationInfo> allAssociations = new ArraySet<>();
+
+        synchronized (mPreviouslyUsedIds) {
+            // The data is stored in DE directories, so we can read the data for all users now
+            // (which would not be possible if the data was stored to CE directories).
+            mPersistentStore.readStateForUsers(
+                    mUserManager.getAliveUsers(), allAssociations, mPreviouslyUsedIds);
+        }
+
+        mAssociationStore = new AssociationStoreImpl(allAssociations);
+        mAssociationStore.registerListener(this);
+
+        mCompanionDevicePresenceController = new CompanionDevicePresenceController(this);
+        mAssociationRequestsProcessor = new AssociationRequestsProcessor(this, mAssociationStore);
+
+        // Publish "binder service"
+        final CompanionDeviceManagerImpl impl = new CompanionDeviceManagerImpl();
+        publishBinderService(Context.COMPANION_DEVICE_SERVICE, impl);
     }
 
     @Override
     public void onBootPhase(int phase) {
         if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
+            registerPackageMonitor();
+
             // Init Bluetooth
             mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
             if (mBluetoothAdapter != null) {
@@ -279,7 +256,7 @@
     @Override
     public void onUserUnlocking(@NonNull TargetUser user) {
         final int userId = user.getUserIdentifier();
-        final Set<AssociationInfo> associations = getAllAssociationsForUser(userId);
+        final List<AssociationInfo> associations = mAssociationStore.getAssociationsForUser(userId);
 
         if (associations.isEmpty()) return;
 
@@ -290,42 +267,18 @@
                 MINUTES.toMillis(10));
     }
 
-    @NonNull
-    Set<AssociationInfo> getAllAssociationsForUser(@UserIdInt int userId) {
-        synchronized (mLock) {
-            readPersistedStateForUserIfNeededLocked(userId);
-            // This returns non-null, because the readAssociationsInfoForUserIfNeededLocked() method
-            // we just called adds an empty set, if there was no previously saved data.
-            return mCachedAssociations.get(userId);
-        }
-    }
-
-    @NonNull
-    Set<AssociationInfo> getAssociations(@UserIdInt int userId, @NonNull String packageName) {
-        return filter(getAllAssociationsForUser(userId),
-                a -> a.belongsToPackage(userId, packageName));
-    }
-
-    @Nullable
-    private AssociationInfo getAssociation(int associationId) {
-        return find(getAllAssociations(), association -> association.getId() == associationId);
-    }
-
-    @Nullable
-    AssociationInfo getAssociation(
-            @UserIdInt int userId, @NonNull String packageName, @NonNull String macAddress) {
-        return find(getAssociations(userId, packageName), a -> a.isLinkedTo(macAddress));
-    }
-
     @Nullable
     AssociationInfo getAssociationWithCallerChecks(
             @UserIdInt int userId, @NonNull String packageName, @NonNull String macAddress) {
-        return sanitizeWithCallerChecks(getAssociation(userId, packageName, macAddress));
+        final AssociationInfo association = mAssociationStore.getAssociationsForPackageWithAddress(
+                userId, packageName, macAddress);
+        return sanitizeWithCallerChecks(association);
     }
 
     @Nullable
     AssociationInfo getAssociationWithCallerChecks(int associationId) {
-        return sanitizeWithCallerChecks(getAssociation(associationId));
+        final AssociationInfo association = mAssociationStore.getAssociationById(associationId);
+        return sanitizeWithCallerChecks(association);
     }
 
     @Nullable
@@ -341,19 +294,6 @@
         return association;
     }
 
-    private Set<AssociationInfo> getAllAssociations() {
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            final Set<AssociationInfo> result = new ArraySet<>();
-            for (UserInfo user : mUserManager.getAliveUsers()) {
-                result.addAll(getAllAssociationsForUser(user.id));
-            }
-            return result;
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
-
     void maybeGrantAutoRevokeExemptions() {
         Slog.d(LOG_TAG, "maybeGrantAutoRevokeExemptions()");
         PackageManager pm = getContext().getPackageManager();
@@ -366,10 +306,8 @@
             }
 
             try {
-                Set<AssociationInfo> associations = getAllAssociationsForUser(userId);
-                if (associations == null) {
-                    continue;
-                }
+                final List<AssociationInfo> associations =
+                        mAssociationStore.getAssociationsForUser(userId);
                 for (AssociationInfo a : associations) {
                     try {
                         int uid = pm.getPackageUidAsUser(a.getPackageName(), userId);
@@ -384,6 +322,61 @@
         }
     }
 
+    @Override
+    public void onAssociationChanged(
+            @AssociationStore.ChangeType int changeType, AssociationInfo association) {
+        final int id = association.getId();
+        final int userId = association.getUserId();
+        final String packageName = association.getPackageName();
+
+        if (changeType == AssociationStore.CHANGE_TYPE_REMOVED) {
+            markIdAsPreviouslyUsedForPackage(id, userId, packageName);
+        }
+
+        final List<AssociationInfo> updatedAssociations =
+                mAssociationStore.getAssociationsForUser(userId);
+        final Map<String, Set<Integer>> usedIdsForUser = getPreviouslyUsedIdsForUser(userId);
+        BackgroundThread.getHandler().post(() ->
+                mPersistentStore.persistStateForUser(userId, updatedAssociations, usedIdsForUser));
+
+        // Notify listeners if ADDED, REMOVED or UPDATED_ADDRESS_CHANGED.
+        // Do NOT notify when UPDATED_ADDRESS_UNCHANGED, which means a minor tweak in association's
+        // configs, which "listeners" won't (and shouldn't) be able to see.
+        if (changeType != CHANGE_TYPE_UPDATED_ADDRESS_UNCHANGED) {
+            notifyListeners(userId, updatedAssociations);
+        }
+        updateAtm(userId, updatedAssociations);
+
+        restartBleScan();
+    }
+
+    private void notifyListeners(
+            @UserIdInt int userId, @NonNull List<AssociationInfo> associations) {
+        mListeners.broadcast((listener, callbackUserId) -> {
+            if ((int) callbackUserId == userId) {
+                try {
+                    listener.onAssociationsChanged(associations);
+                } catch (RemoteException ignored) {
+                }
+            }
+        });
+    }
+
+    private void markIdAsPreviouslyUsedForPackage(
+            int associationId, @UserIdInt int userId, @NonNull String packageName) {
+        synchronized (mPreviouslyUsedIds) {
+            Map<String, Set<Integer>> usedIdsForUser = mPreviouslyUsedIds.get(userId);
+            if (usedIdsForUser == null) {
+                usedIdsForUser = new HashMap<>();
+                mPreviouslyUsedIds.put(userId, usedIdsForUser);
+            }
+
+            final Set<Integer> usedIdsForPackage =
+                    usedIdsForUser.computeIfAbsent(packageName, it -> new HashSet<>());
+            usedIdsForPackage.add(associationId);
+        }
+    }
+
     class CompanionDeviceManagerImpl extends ICompanionDeviceManager.Stub {
 
         @Override
@@ -421,8 +414,7 @@
                 checkUsesFeature(packageName, getCallingUserId());
             }
 
-            return new ArrayList<>(
-                    CompanionDeviceManagerService.this.getAssociations(userId, packageName));
+            return mAssociationStore.getAssociationsForPackage(userId, packageName);
         }
 
         @Override
@@ -430,8 +422,7 @@
             enforceCallerCanInteractWithUserId(getContext(), userId);
             enforceCallerCanManageCompanionDevice(getContext(), "getAllAssociationsForUser");
 
-            return new ArrayList<>(
-                    CompanionDeviceManagerService.this.getAllAssociationsForUser(userId));
+            return mAssociationStore.getAssociationsForUser(userId);
         }
 
         @Override
@@ -441,13 +432,17 @@
             enforceCallerCanManageCompanionDevice(getContext(),
                     "addOnAssociationsChangedListener");
 
-            //TODO: Implement.
+            mListeners.register(listener, userId);
         }
 
         @Override
         public void removeOnAssociationsChangedListener(IOnAssociationsChangedListener listener,
                 int userId) {
-            //TODO: Implement.
+            enforceCallerCanInteractWithUserId(getContext(), userId);
+            enforceCallerCanManageCompanionDevice(
+                    getContext(), "removeOnAssociationsChangedListener");
+
+            mListeners.unregister(listener);
         }
 
         @Override
@@ -463,7 +458,7 @@
                         + "(ie. it belongs to a different package or a different user).");
             }
 
-            disassociateInternal(userId, association.getId());
+            disassociateInternal(association.getId());
         }
 
         @Override
@@ -476,7 +471,7 @@
                         + "or belongs to a different user");
             }
 
-            disassociateInternal(association.getUserId(), associationId);
+            disassociateInternal(associationId);
         }
 
         @Override
@@ -533,7 +528,7 @@
                 return true;
             }
 
-            return any(CompanionDeviceManagerService.this.getAssociations(userId, packageName),
+            return any(mAssociationStore.getAssociationsForPackage(userId, packageName),
                     a -> a.isLinkedTo(macAddress));
         }
 
@@ -616,25 +611,18 @@
             final int userId = getCallingUserId();
             enforceCallerIsSystemOr(userId, packageName);
 
-            Set<AssociationInfo> deviceAssociations = filter(
-                    CompanionDeviceManagerService.this.getAssociations(userId, packageName),
-                    a -> a.isLinkedTo(deviceAddress));
+            final AssociationInfo association =
+                    mAssociationStore.getAssociationsForPackageWithAddress(
+                            userId, packageName, deviceAddress);
 
-            if (deviceAssociations.isEmpty()) {
+            if (association == null) {
                 throw new RemoteException(new DeviceNotAssociatedException("App " + packageName
                         + " is not associated with device " + deviceAddress
                         + " for user " + userId));
             }
 
-            updateAssociations(associations -> map(associations, association -> {
-                if (association.belongsToPackage(userId, packageName)
-                        && association.isLinkedTo(deviceAddress)) {
-                    association.setNotifyOnDeviceNearby(active);
-                }
-                return association;
-            }), userId);
-
-            restartBleScan();
+            association.setNotifyOnDeviceNearby(active);
+            mAssociationStore.updateAssociation(association);
         }
 
         @Override
@@ -657,14 +645,16 @@
             enforceCallerIsSystemOr(userId, callingPackage);
 
             checkState(!ArrayUtils.isEmpty(
-                    CompanionDeviceManagerService.this.getAssociations(userId, callingPackage)),
+                    mAssociationStore.getAssociationsForPackage(userId, callingPackage)),
                     "App must have an association before calling this API");
             checkUsesFeature(callingPackage, userId);
         }
 
         @Override
         public boolean canPairWithoutPrompt(String packageName, String macAddress, int userId) {
-            final AssociationInfo association = getAssociation(userId, packageName, macAddress);
+            final AssociationInfo association =
+                    mAssociationStore.getAssociationsForPackageWithAddress(
+                            userId, packageName, macAddress);
             if (association == null) {
                 return false;
             }
@@ -677,7 +667,8 @@
                 String[] args, ShellCallback callback, ResultReceiver resultReceiver)
                 throws RemoteException {
             enforceCallerCanManageCompanionDevice(getContext(), "onShellCommand");
-            new CompanionDeviceShellCommand(CompanionDeviceManagerService.this)
+            new CompanionDeviceShellCommand(
+                    CompanionDeviceManagerService.this, mAssociationStore)
                     .exec(this, in, out, err, args, callback, resultReceiver);
         }
 
@@ -690,13 +681,8 @@
             }
 
             fout.append("Companion Device Associations:").append('\n');
-            synchronized (mLock) {
-                for (UserInfo user : getAllUsers()) {
-                    forEach(mCachedAssociations.get(user.id), a -> {
-                        fout.append("  ").append(a.toString()).append('\n');
-                    });
-                }
-
+            for (AssociationInfo a : mAssociationStore.getAssociations()) {
+                fout.append("  ").append(a.toString()).append('\n');
             }
 
             fout.append("Currently Connected Devices:").append('\n');
@@ -747,31 +733,56 @@
             @Nullable String deviceProfile, boolean selfManaged) {
         final int id = getNewAssociationIdForPackage(userId, packageName);
         final long timestamp = System.currentTimeMillis();
+
         final AssociationInfo association = new AssociationInfo(id, userId, packageName,
                 macAddress, displayName, deviceProfile, selfManaged, false, timestamp);
+        Slog.i(LOG_TAG, "New CDM association created=" + association);
+        mAssociationStore.addAssociation(association);
 
         updateSpecialAccessPermissionForAssociatedPackage(association);
-        recordAssociation(association, userId);
 
         return association;
     }
 
-    @GuardedBy("mLock")
+    @NonNull
+    private Map<String, Set<Integer>> getPreviouslyUsedIdsForUser(@UserIdInt int userId) {
+        synchronized (mPreviouslyUsedIds) {
+            return getPreviouslyUsedIdsForUserLocked(userId);
+        }
+    }
+
+    @GuardedBy("mPreviouslyUsedIds")
+    @NonNull
+    private Map<String, Set<Integer>> getPreviouslyUsedIdsForUserLocked(@UserIdInt int userId) {
+        final Map<String, Set<Integer>> usedIdsForUser = mPreviouslyUsedIds.get(userId);
+        if (usedIdsForUser == null) {
+            return Collections.emptyMap();
+        }
+        return deepUnmodifiableCopy(usedIdsForUser);
+    }
+
+    @GuardedBy("mPreviouslyUsedIds")
     @NonNull
     private Set<Integer> getPreviouslyUsedIdsForPackageLocked(
             @UserIdInt int userId, @NonNull String packageName) {
-        final Set<Integer> previouslyUsedIds = mPreviouslyUsedIds.get(userId).get(packageName);
-        if (previouslyUsedIds != null) return previouslyUsedIds;
-        return emptySet();
+        // "Deeply unmodifiable" map: the map itself and the Set<Integer> values it contains are all
+        // unmodifiable.
+        final Map<String, Set<Integer>> usedIdsForUser = getPreviouslyUsedIdsForUserLocked(userId);
+        final Set<Integer> usedIdsForPackage = usedIdsForUser.get(packageName);
+
+        if (usedIdsForPackage == null) {
+            return Collections.emptySet();
+        }
+
+        //The set is already unmodifiable.
+        return usedIdsForPackage;
     }
 
     private int getNewAssociationIdForPackage(@UserIdInt int userId, @NonNull String packageName) {
-        synchronized (mLock) {
-            readPersistedStateForUserIfNeededLocked(userId);
-
+        synchronized (mPreviouslyUsedIds) {
             // First: collect all IDs currently in use for this user's Associations.
             final SparseBooleanArray usedIds = new SparseBooleanArray();
-            for (AssociationInfo it : getAllAssociationsForUser(userId)) {
+            for (AssociationInfo it : mAssociationStore.getAssociationsForUser(userId)) {
                 usedIds.put(it.getId(), true);
             }
 
@@ -797,41 +808,14 @@
         }
     }
 
-    //TODO also revoke notification access
-    void disassociateInternal(@UserIdInt int userId, int associationId) {
-        updateAssociations(associations ->
-                filterOut(associations, it -> {
-                    if (it.getId() != associationId) return false;
-
-                    onAssociationPreRemove(it);
-                    markIdAsPreviouslyUsedForPackage(
-                            it.getId(), it.getUserId(), it.getPackageName());
-                    return true;
-                }), userId);
-
-        restartBleScan();
+    //TODO: also revoke notification access
+    void disassociateInternal(int associationId) {
+        onAssociationPreRemove(associationId);
+        mAssociationStore.removeAssociation(associationId);
     }
 
-    void clearAssociationForPackage(@UserIdInt int userId, @NonNull String packageName) {
-        if (DEBUG) Slog.d(LOG_TAG, "clearAssociationForPackage() u" + userId + "/" + packageName);
-
-        mCompanionDevicePresenceController.unbindDevicePresenceListener(packageName, userId);
-        updateAssociations(set -> filterOut(set, it -> it.belongsToPackage(userId, packageName)),
-                userId);
-    }
-
-    private void markIdAsPreviouslyUsedForPackage(
-            int associationId, @UserIdInt int userId, @NonNull String packageName) {
-        synchronized (mLock) {
-            // Mark as previously used.
-            readPersistedStateForUserIfNeededLocked(userId);
-            mPreviouslyUsedIds.get(userId)
-                    .computeIfAbsent(packageName, it -> new HashSet<>())
-                    .add(associationId);
-        }
-    }
-
-    void onAssociationPreRemove(AssociationInfo association) {
+    void onAssociationPreRemove(int associationId) {
+        final AssociationInfo association = mAssociationStore.getAssociationById(associationId);
         if (association.isNotifyOnDeviceNearby()
                 || (association.isSelfManaged()
                 && mPresentSelfManagedDevices.contains(association.getId()))) {
@@ -842,7 +826,7 @@
         String deviceProfile = association.getDeviceProfile();
         if (deviceProfile != null) {
             AssociationInfo otherAssociationWithDeviceProfile = find(
-                    getAllAssociationsForUser(association.getUserId()),
+                    mAssociationStore.getAssociationsForUser(association.getUserId()),
                     a -> !a.equals(association) && deviceProfile.equals(a.getDeviceProfile()));
             if (otherAssociationWithDeviceProfile != null) {
                 Slog.i(LOG_TAG, "Not revoking " + deviceProfile
@@ -934,37 +918,7 @@
                         .getPackageInfoAsUser(packageName, flags , userId));
     }
 
-    private void recordAssociation(AssociationInfo association, int userId) {
-        Slog.i(LOG_TAG, "recordAssociation(" + association + ")");
-        updateAssociations(associations -> add(associations, association), userId);
-    }
-
-    private void updateAssociations(Function<Set<AssociationInfo>, Set<AssociationInfo>> update,
-            int userId) {
-        synchronized (mLock) {
-            if (DEBUG) Slog.d(LOG_TAG, "Updating Associations set...");
-
-            final Set<AssociationInfo> prevAssociations = getAllAssociationsForUser(userId);
-            if (DEBUG) Slog.d(LOG_TAG, "  > Before : " + prevAssociations + "...");
-
-            final Set<AssociationInfo> updatedAssociations = update.apply(
-                    new ArraySet<>(prevAssociations));
-            if (DEBUG) Slog.d(LOG_TAG, "  > After: " + updatedAssociations);
-
-            mCachedAssociations.put(userId, unmodifiableSet(updatedAssociations));
-
-            BackgroundThread.getHandler().sendMessage(
-                    PooledLambda.obtainMessage(
-                            (associations, usedIds) ->
-                                    mPersistentDataStore
-                                            .persistStateForUser(userId, associations, usedIds),
-                            updatedAssociations, deepCopy(mPreviouslyUsedIds.get(userId))));
-
-            updateAtm(userId, updatedAssociations);
-        }
-    }
-
-    private void updateAtm(int userId, Set<AssociationInfo> associations) {
+    private void updateAtm(int userId, List<AssociationInfo> associations) {
         final Set<Integer> companionAppUids = new ArraySet<>();
         for (AssociationInfo association : associations) {
             final int uid = mPackageManagerInternal.getPackageUid(association.getPackageName(),
@@ -973,59 +927,24 @@
                 companionAppUids.add(uid);
             }
         }
-        if (mAtmInternal != null) {
-            mAtmInternal.setCompanionAppUids(userId, companionAppUids);
-        }
         if (mAmInternal != null) {
-            // Make a copy of companionAppUids and send it to ActivityManager.
+            // Make a copy of the set and send it to ActivityManager.
             mAmInternal.setCompanionAppUids(userId, new ArraySet<>(companionAppUids));
         }
     }
 
-    @GuardedBy("mLock")
-    private void readPersistedStateForUserIfNeededLocked(@UserIdInt int userId) {
-        if (mCachedAssociations.get(userId) != null) return;
-
-        Slog.i(LOG_TAG, "Reading state for user " + userId + "  from the disk");
-
-        final Set<AssociationInfo> associations = new ArraySet<>();
-        final Map<String, Set<Integer>> previouslyUsedIds = new ArrayMap<>();
-        mPersistentDataStore.readStateForUser(userId, associations, previouslyUsedIds);
-
-        if (DEBUG) {
-            Slog.d(LOG_TAG, "  > associations=" + associations + "\n"
-                    + "  > previouslyUsedIds=" + previouslyUsedIds);
-        }
-
-        mCachedAssociations.put(userId, unmodifiableSet(associations));
-        mPreviouslyUsedIds.append(userId, previouslyUsedIds);
-    }
-
-    private List<UserInfo> getAllUsers() {
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            return mUserManager.getUsers();
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
-
     void onDeviceConnected(String address) {
         Slog.d(LOG_TAG, "onDeviceConnected(address = " + address + ")");
 
         mCurrentlyConnectedDevices.add(address);
 
-        for (UserInfo user : getAllUsers()) {
-            for (AssociationInfo association : getAllAssociationsForUser(user.id)) {
-                if (association.isLinkedTo(address)) {
-                    if (association.getDeviceProfile() != null) {
-                        Slog.i(LOG_TAG, "Granting role " + association.getDeviceProfile()
-                                + " to " + association.getPackageName()
-                                + " due to device connected: " + association.getDeviceMacAddress());
+        for (AssociationInfo association : mAssociationStore.getAssociationsByAddress(address)) {
+            if (association.getDeviceProfile() != null) {
+                Slog.i(LOG_TAG, "Granting role " + association.getDeviceProfile()
+                        + " to " + association.getPackageName()
+                        + " due to device connected: " + association.getDeviceMacAddress());
 
-                        addRoleHolderForAssociation(getContext(), association);
-                    }
-                }
+                addRoleHolderForAssociation(getContext(), association);
             }
         }
 
@@ -1118,7 +1037,9 @@
                 Date lastNearby = mDevicesLastNearby.valueAt(i);
 
                 if (isDeviceDisappeared(lastNearby)) {
-                    for (AssociationInfo association : getAllAssociations(address)) {
+                    final List<AssociationInfo> associations =
+                            mAssociationStore.getAssociationsByAddress(address);
+                    for (AssociationInfo association : associations) {
                         if (association.isNotifyOnDeviceNearby()) {
                             mCompanionDevicePresenceController.unbindDevicePresenceListener(
                                     association.getPackageName(), association.getUserId());
@@ -1160,20 +1081,6 @@
         }
     }
 
-    private Set<AssociationInfo> getAllAssociations(String deviceAddress) {
-        List<UserInfo> aliveUsers = mUserManager.getAliveUsers();
-        Set<AssociationInfo> result = new ArraySet<>();
-        for (int i = 0, size = aliveUsers.size(); i < size; i++) {
-            UserInfo user = aliveUsers.get(i);
-            for (AssociationInfo association : getAllAssociationsForUser(user.id)) {
-                if (association.isLinkedTo(deviceAddress)) {
-                    result.add(association);
-                }
-            }
-        }
-        return result;
-    }
-
     private void onDeviceNearby(String address) {
         Date timestamp = new Date();
         Date oldTimestamp = mDevicesLastNearby.put(address, timestamp);
@@ -1189,7 +1096,9 @@
                 || timestamp.getTime() - oldTimestamp.getTime() >= DEVICE_DISAPPEARED_TIMEOUT_MS;
         if (justAppeared) {
             Slog.i(LOG_TAG, "onDeviceNearby(justAppeared, address = " + address + ")");
-            for (AssociationInfo association : getAllAssociations(address)) {
+            final List<AssociationInfo> associations =
+                    mAssociationStore.getAssociationsByAddress(address);
+            for (AssociationInfo association : associations) {
                 if (association.isNotifyOnDeviceNearby()) {
                     mCompanionDevicePresenceController.onDeviceNotifyAppeared(association,
                             getContext(), mMainHandler);
@@ -1202,7 +1111,9 @@
         Slog.i(LOG_TAG, "onDeviceDisappeared(address = " + address + ")");
 
         boolean hasDeviceListeners = false;
-        for (AssociationInfo association : getAllAssociations(address)) {
+        final List<AssociationInfo> associations =
+                mAssociationStore.getAssociationsByAddress(address);
+        for (AssociationInfo association : associations) {
             if (association.isNotifyOnDeviceNearby()) {
                 mCompanionDevicePresenceController.onDeviceNotifyDisappeared(
                         association, getContext(), mMainHandler);
@@ -1275,7 +1186,7 @@
     private List<ScanFilter> getBleScanFilters() {
         ArrayList<ScanFilter> result = new ArrayList<>();
         ArraySet<String> addressesSeen = new ArraySet<>();
-        for (AssociationInfo association : getAllAssociations()) {
+        for (AssociationInfo association : mAssociationStore.getAssociations()) {
             if (association.isSelfManaged()) {
                 continue;
             }
@@ -1315,17 +1226,6 @@
         }
     }
 
-    private static @NonNull <T> Set<T> filterOut(
-            @NonNull Set<T> set, @NonNull Predicate<? super T> predicate) {
-        return CollectionUtils.filter(set, predicate.negate());
-    }
-
-    private Map<String, Set<Integer>> deepCopy(Map<String, Set<Integer>> orig) {
-        final Map<String, Set<Integer>> copy = new HashMap<>(orig.size(), 1f);
-        forEach(orig, (key, value) -> copy.put(key, new ArraySet<>(value)));
-        return copy;
-    }
-
     void checkUsesFeature(@NonNull String pkg, @UserIdInt int userId) {
         if (getCallingUid() == SYSTEM_UID) return;
 
@@ -1340,4 +1240,61 @@
                 + FEATURE_COMPANION_DEVICE_SETUP
                 + " in manifest to use this API");
     }
+
+    private void registerPackageMonitor() {
+        new PackageMonitor() {
+            @Override
+            public void onPackageRemoved(String packageName, int uid) {
+                final int userId = getChangingUserId();
+                Slog.i(LOG_TAG, "onPackageRemoved() u" + userId + "/" + packageName);
+
+                clearAssociationForPackage(userId, packageName);
+            }
+
+            @Override
+            public void onPackageDataCleared(String packageName, int uid) {
+                final int userId = getChangingUserId();
+                Slog.i(LOG_TAG, "onPackageDataCleared() u" + userId + "/" + packageName);
+
+                clearAssociationForPackage(userId, packageName);
+            }
+
+            @Override
+            public void onPackageModified(String packageName) {
+                final int userId = getChangingUserId();
+                Slog.i(LOG_TAG, "onPackageModified() u" + userId + "/" + packageName);
+
+                final List<AssociationInfo> associationsForPackage =
+                        mAssociationStore.getAssociationsForPackage(userId, packageName);
+                for (AssociationInfo association : associationsForPackage) {
+                    updateSpecialAccessPermissionForAssociatedPackage(association);
+                }
+            }
+        }.register(getContext(), FgThread.get().getLooper(), UserHandle.ALL, true);
+    }
+
+    private void clearAssociationForPackage(@UserIdInt int userId, @NonNull String packageName) {
+        if (DEBUG) Slog.d(LOG_TAG, "clearAssociationForPackage() u" + userId + "/" + packageName);
+
+        // First, unbind CompanionService if needed.
+        mCompanionDevicePresenceController.unbindDevicePresenceListener(packageName, userId);
+
+        // Clear associations.
+        final List<AssociationInfo> associationsForPackage =
+                mAssociationStore.getAssociationsForPackage(userId, packageName);
+        for (AssociationInfo association : associationsForPackage) {
+            mAssociationStore.removeAssociation(association.getId());
+        }
+    }
+
+    private static Map<String, Set<Integer>> deepUnmodifiableCopy(Map<String, Set<Integer>> orig) {
+        final Map<String, Set<Integer>> copy = new HashMap<>();
+
+        for (Map.Entry<String, Set<Integer>> entry : orig.entrySet()) {
+            final Set<Integer> valueCopy = new HashSet<>(entry.getValue());
+            copy.put(entry.getKey(), Collections.unmodifiableSet(valueCopy));
+        }
+
+        return Collections.unmodifiableMap(copy);
+    }
 }
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java b/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
index 5cb3079..5c0571d 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
@@ -16,7 +16,6 @@
 
 package com.android.server.companion;
 
-import static com.android.internal.util.CollectionUtils.forEach;
 import static com.android.server.companion.CompanionDeviceManagerService.LOG_TAG;
 
 import android.companion.AssociationInfo;
@@ -24,24 +23,33 @@
 import android.util.Slog;
 
 import java.io.PrintWriter;
+import java.util.List;
 
 class CompanionDeviceShellCommand extends android.os.ShellCommand {
     private final CompanionDeviceManagerService mService;
+    private final AssociationStore mAssociationStore;
 
-    CompanionDeviceShellCommand(CompanionDeviceManagerService service) {
+    CompanionDeviceShellCommand(CompanionDeviceManagerService service,
+            AssociationStore associationStore) {
         mService = service;
+        mAssociationStore = associationStore;
     }
 
     @Override
     public int onCommand(String cmd) {
+        final PrintWriter out = getOutPrintWriter();
         try {
             switch (cmd) {
                 case "list": {
-                    forEach(
-                            mService.getAllAssociationsForUser(getNextArgInt()),
-                            a -> getOutPrintWriter()
-                                    .println(a.getPackageName() + " "
-                                            + a.getDeviceMacAddress()));
+                    final int userId = getNextArgInt();
+                    final List<AssociationInfo> associationsForUser =
+                            mAssociationStore.getAssociationsForUser(userId);
+                    for (AssociationInfo association : associationsForUser) {
+                        // TODO(b/212535524): use AssociationInfo.toShortString(), once it's not
+                        //  longer referenced in tests.
+                        out.println(association.getPackageName() + " "
+                                + association.getDeviceMacAddress());
+                    }
                 }
                 break;
 
@@ -60,7 +68,7 @@
                     final AssociationInfo association =
                             mService.getAssociationWithCallerChecks(userId, packageName, address);
                     if (association != null) {
-                        mService.disassociateInternal(userId, association.getId());
+                        mService.disassociateInternal(association.getId());
                     }
                 }
                 break;
diff --git a/services/companion/java/com/android/server/companion/PersistentDataStore.java b/services/companion/java/com/android/server/companion/PersistentDataStore.java
index 87558df..97ec3bb 100644
--- a/services/companion/java/com/android/server/companion/PersistentDataStore.java
+++ b/services/companion/java/com/android/server/companion/PersistentDataStore.java
@@ -33,15 +33,18 @@
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.companion.AssociationInfo;
+import android.content.pm.UserInfo;
 import android.net.MacAddress;
 import android.os.Environment;
+import android.util.ArrayMap;
 import android.util.AtomicFile;
-import android.util.ExceptionUtils;
 import android.util.Slog;
+import android.util.SparseArray;
 import android.util.TypedXmlPullParser;
 import android.util.TypedXmlSerializer;
 import android.util.Xml;
 
+import com.android.internal.util.FunctionalUtils.ThrowingConsumer;
 import com.android.internal.util.XmlUtils;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -50,8 +53,11 @@
 
 import java.io.File;
 import java.io.FileInputStream;
+import java.io.FileOutputStream;
 import java.io.IOException;
+import java.util.Collection;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
@@ -68,8 +74,8 @@
  *
  * Before Android T the data was stored using the v0 schema.
  *
- * @see #readAssociationsV0(TypedXmlPullParser, int, Set)
- * @see #readAssociationV0(TypedXmlPullParser, int, int, Set)
+ * @see #readAssociationsV0(TypedXmlPullParser, int, Collection)
+ * @see #readAssociationV0(TypedXmlPullParser, int, int, Collection)
  *
  * The following snippet is a sample of a the file that is using v0 schema.
  * <pre>{@code
@@ -100,8 +106,8 @@
  * optional.
  *
  * @see #CURRENT_PERSISTENCE_VERSION
- * @see #readAssociationsV1(TypedXmlPullParser, int, Set)
- * @see #readAssociationV1(TypedXmlPullParser, int, Set)
+ * @see #readAssociationsV1(TypedXmlPullParser, int, Collection)
+ * @see #readAssociationV1(TypedXmlPullParser, int, Collection)
  * @see #readPreviouslyUsedIdsV1(TypedXmlPullParser, Map)
  *
  * The following snippet is a sample of a the file that is using v0 schema.
@@ -168,6 +174,23 @@
     private final @NonNull ConcurrentMap<Integer, AtomicFile> mUserIdToStorageFile =
             new ConcurrentHashMap<>();
 
+    void readStateForUsers(@NonNull List<UserInfo> users,
+            @NonNull Set<AssociationInfo> allAssociationsOut,
+            @NonNull SparseArray<Map<String, Set<Integer>>> previouslyUsedIdsPerUserOut) {
+        for (UserInfo user : users) {
+            final int userId = user.id;
+            // Previously used IDs are stored in the "out" collection per-user.
+            final Map<String, Set<Integer>> previouslyUsedIds = new ArrayMap<>();
+
+            // Associations for all users are stored in a single "flat" set: so we read directly
+            // into it.
+            readStateForUser(userId, allAssociationsOut, previouslyUsedIds);
+
+            // Save previously used IDs for this user into the "out" structure.
+            previouslyUsedIdsPerUserOut.append(userId, previouslyUsedIds);
+        }
+    }
+
     /**
      * Reads previously persisted data for the given user "into" the provided containers.
      *
@@ -176,7 +199,7 @@
      * @param previouslyUsedIdsPerPackageOut a container to read the used IDs "into".
      */
     void readStateForUser(@UserIdInt int userId,
-            @NonNull Set<AssociationInfo> associationsOut,
+            @NonNull Collection<AssociationInfo> associationsOut,
             @NonNull Map<String, Set<Integer>> previouslyUsedIdsPerPackageOut) {
         Slog.i(LOG_TAG, "Reading associations for user " + userId + " from disk");
         final AtomicFile file = getStorageFileForUser(userId);
@@ -237,7 +260,8 @@
      * @param associations a set of user's associations.
      * @param previouslyUsedIdsPerPackage a set previously used Association IDs for the user.
      */
-    void persistStateForUser(@UserIdInt int userId, @NonNull Set<AssociationInfo> associations,
+    void persistStateForUser(@UserIdInt int userId,
+            @NonNull Collection<AssociationInfo> associations,
             @NonNull Map<String, Set<Integer>> previouslyUsedIdsPerPackage) {
         Slog.i(LOG_TAG, "Writing associations for user " + userId + " to disk");
         if (DEBUG) Slog.d(LOG_TAG, "  > " + associations);
@@ -250,7 +274,7 @@
     }
 
     private int readStateFromFileLocked(@UserIdInt int userId, @NonNull AtomicFile file,
-            @NonNull String rootTag, @Nullable Set<AssociationInfo> associationsOut,
+            @NonNull String rootTag, @Nullable Collection<AssociationInfo> associationsOut,
             @NonNull Map<String, Set<Integer>> previouslyUsedIdsPerPackageOut) {
         try (FileInputStream in = file.openRead()) {
             final TypedXmlPullParser parser = Xml.resolvePullParser(in);
@@ -282,28 +306,25 @@
     }
 
     private void persistStateToFileLocked(@NonNull AtomicFile file,
-            @Nullable Set<AssociationInfo> associations,
+            @Nullable Collection<AssociationInfo> associations,
             @NonNull Map<String, Set<Integer>> previouslyUsedIdsPerPackage) {
-        file.write(out -> {
-            try {
-                final TypedXmlSerializer serializer = Xml.resolveSerializer(out);
-                serializer.setFeature(
-                        "http://xmlpull.org/v1/doc/features.html#indent-output", true);
+        // Writing to file could fail, for example, if the user has been recently removed and so was
+        // their DE (/data/system_de/<user-id>/) directory.
+        writeToFileSafely(file, out -> {
+            final TypedXmlSerializer serializer = Xml.resolveSerializer(out);
+            serializer.setFeature(
+                    "http://xmlpull.org/v1/doc/features.html#indent-output", true);
 
-                serializer.startDocument(null, true);
-                serializer.startTag(null, XML_TAG_STATE);
-                writeIntAttribute(serializer,
-                        XML_ATTR_PERSISTENCE_VERSION, CURRENT_PERSISTENCE_VERSION);
+            serializer.startDocument(null, true);
+            serializer.startTag(null, XML_TAG_STATE);
+            writeIntAttribute(serializer,
+                    XML_ATTR_PERSISTENCE_VERSION, CURRENT_PERSISTENCE_VERSION);
 
-                writeAssociations(serializer, associations);
-                writePreviouslyUsedIds(serializer, previouslyUsedIdsPerPackage);
+            writeAssociations(serializer, associations);
+            writePreviouslyUsedIds(serializer, previouslyUsedIdsPerPackage);
 
-                serializer.endTag(null, XML_TAG_STATE);
-                serializer.endDocument();
-            } catch (Exception e) {
-                Slog.e(LOG_TAG, "Error while writing associations file", e);
-                throw ExceptionUtils.propagate(e);
-            }
+            serializer.endTag(null, XML_TAG_STATE);
+            serializer.endDocument();
         });
     }
 
@@ -321,7 +342,7 @@
     }
 
     private static void readAssociationsV0(@NonNull TypedXmlPullParser parser,
-            @UserIdInt int userId, @NonNull Set<AssociationInfo> out)
+            @UserIdInt int userId, @NonNull Collection<AssociationInfo> out)
             throws XmlPullParserException, IOException {
         requireStartOfTag(parser, XML_TAG_ASSOCIATIONS);
 
@@ -342,7 +363,8 @@
     }
 
     private static void readAssociationV0(@NonNull TypedXmlPullParser parser, @UserIdInt int userId,
-            int associationId, @NonNull Set<AssociationInfo> out) throws XmlPullParserException {
+            int associationId, @NonNull Collection<AssociationInfo> out)
+            throws XmlPullParserException {
         requireStartOfTag(parser, XML_TAG_ASSOCIATION);
 
         final String appPackage = readStringAttribute(parser, XML_ATTR_PACKAGE);
@@ -360,7 +382,7 @@
     }
 
     private static void readAssociationsV1(@NonNull TypedXmlPullParser parser,
-            @UserIdInt int userId, @NonNull Set<AssociationInfo> out)
+            @UserIdInt int userId, @NonNull Collection<AssociationInfo> out)
             throws XmlPullParserException, IOException {
         requireStartOfTag(parser, XML_TAG_ASSOCIATIONS);
 
@@ -374,7 +396,7 @@
     }
 
     private static void readAssociationV1(@NonNull TypedXmlPullParser parser, @UserIdInt int userId,
-            @NonNull Set<AssociationInfo> out) throws XmlPullParserException, IOException {
+            @NonNull Collection<AssociationInfo> out) throws XmlPullParserException, IOException {
         requireStartOfTag(parser, XML_TAG_ASSOCIATION);
 
         final int associationId = readIntAttribute(parser, XML_ATTR_ID);
@@ -421,9 +443,11 @@
     }
 
     private static void writeAssociations(@NonNull XmlSerializer parent,
-            @Nullable Set<AssociationInfo> associations) throws IOException {
+            @Nullable Collection<AssociationInfo> associations) throws IOException {
         final XmlSerializer serializer = parent.startTag(null, XML_TAG_ASSOCIATIONS);
-        forEach(associations, it -> writeAssociation(serializer, it));
+        for (AssociationInfo association : associations) {
+            writeAssociation(serializer, association);
+        }
         serializer.endTag(null, XML_TAG_ASSOCIATIONS);
     }
 
@@ -498,4 +522,13 @@
         }
         return associationInfo;
     }
+
+    private static void writeToFileSafely(@NonNull AtomicFile file,
+            @NonNull ThrowingConsumer<FileOutputStream> consumer) {
+        try {
+            file.write(consumer);
+        } catch (Exception e) {
+            Slog.e(LOG_TAG, "Error while writing to file " + file, e);
+        }
+    }
 }
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 826b16a..7b17162 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -163,6 +163,7 @@
         "android.hardware.oemlock-V1.0-java",
         "android.hardware.configstore-V1.1-java",
         "android.hardware.contexthub-V1.0-java",
+        "android.hardware.ir-V1-java",
         "android.hardware.rebootescrow-V1-java",
         "android.hardware.soundtrigger-V2.3-java",
         "android.hardware.power.stats-V1-java",
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index 6fe2806..9b2948f 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -50,6 +50,7 @@
 import com.android.server.pm.pkg.AndroidPackageApi;
 import com.android.server.pm.pkg.PackageState;
 import com.android.server.pm.pkg.PackageStateInternal;
+import com.android.server.pm.pkg.mutate.PackageStateMutator;
 
 import java.io.IOException;
 import java.lang.annotation.Retention;
@@ -885,17 +886,6 @@
     public abstract boolean userNeedsBadging(int userId);
 
     /**
-     * Perform the given action for each package.
-     * Note that packages lock will be held while performing the actions.
-     *
-     * If the caller does not need all packages, prefer the potentially non-locking
-     * {@link #withPackageSettingsSnapshot(Consumer)}.
-     *
-     * @param actionLocked action to be performed
-     */
-    public abstract void forEachPackage(Consumer<AndroidPackage> actionLocked);
-
-    /**
      * Perform the given action for each {@link PackageSetting}.
      * Note that packages lock will be held while performing the actions.
      *
@@ -918,12 +908,24 @@
     public abstract void forEachPackageState(boolean locked, Consumer<PackageStateInternal> action);
 
     /**
+     * {@link #forEachPackageState(boolean, Consumer)} but filtered to only states with packages
+     * on device where {@link PackageStateInternal#getPkg()} is not null.
+     */
+    public abstract void forEachPackage(Consumer<AndroidPackage> action);
+
+    /**
      * Perform the given action for each installed package for a user.
      * Note that packages lock will be held while performing the actions.
      */
     public abstract void forEachInstalledPackage(
             @NonNull Consumer<AndroidPackage> actionLocked, @UserIdInt int userId);
 
+    /**
+     * Perform the given action for each installed package for a user.
+     */
+    public abstract void forEachInstalledPackage(boolean locked,
+            @NonNull Consumer<AndroidPackage> action, @UserIdInt int userId);
+
     /** Returns the list of enabled components */
     public abstract ArraySet<String> getEnabledComponents(String packageName, int userId);
 
@@ -1265,4 +1267,62 @@
      */
     public abstract void reconcileAppsData(int userId, @StorageManager.StorageFlags int flags,
             boolean migrateAppsData);
+
+    /**
+     * Initiates a package state mutation request, returning the current state as known by
+     * PackageManager. This allows the later commit request to compare the initial values and
+     * determine if any state was changed or any packages were updated since the whole request
+     * was initiated.
+     *
+     * As a concrete example, consider the following steps:
+     * <ol>
+     *     <li>Read a package state without taking a lock</li>
+     *     <li>Check some values in that state, determine that a mutation needs to occur</li>
+     *     <li>Call to commit the change with the new value, takes lock</li>
+     * </ol>
+     *
+     * Between steps 1 and 3, because the lock was not taken for the entire flow, it's possible
+     * a package state was changed by another consumer or a package was updated/installed.
+     *
+     * If anything has changed,
+     * {@link #commitPackageStateMutation(PackageStateMutator.InitialState, Consumer)} will return
+     * a {@link PackageStateMutator.Result} indicating so. If the caller has not indicated it can
+     * ignore changes, it can opt to re-run the commit logic from the top with a true write lock
+     * around all of its read-logic-commit loop.
+     *
+     * Note that if the caller does not care about potential race conditions or package/state
+     * changes between steps 1 and 3, it can simply opt to not call this method and pass in null
+     * for the initial state. This is useful to avoid long running data structure locks when the
+     * caller is changing a value as part of a one-off request. Perhaps from an app side API which
+     * mutates only a single package, where it doesn't care what the state of that package is or
+     * any other packages on the devices.
+     *
+     * Important to note is that if no locking is enforced, callers themselves will not be
+     * synchronized with themselves. The caller may be relying on the PackageManager lock to
+     * enforce ordering within their own code path, and that has to be adjusted if migrated off
+     * the lock.
+     */
+    @NonNull
+    public abstract PackageStateMutator.InitialState recordInitialState();
+
+    /**
+     * Some questions to ask when designing a mutation:
+     * <ol>
+     *     <li>What external system state is required and is it synchronized properly?</li>
+     *     <li>Are there any package/state changes that could happen to the target (or another)
+     *     package that could result in the commit being invalid?</li>
+     *     <li>Is the caller synchronized with itself and can handle multiple mutations being
+     *     requested from different threads?</li>
+     *     <li>What should be done in case of a conflict and the commit can't be finished?</li>
+     * </ol>
+     *
+     * @param state See {@link #recordInitialState()}. If null, no result is returned.
+     * @param consumer Lean wrapper around just the logic that changes state values
+     * @return result if anything changed since initial state, or null if nothing changed and
+     * commit was successful
+     */
+    @Nullable
+    public abstract PackageStateMutator.Result commitPackageStateMutation(
+            @Nullable PackageStateMutator.InitialState state,
+            @NonNull Consumer<PackageStateMutator> consumer);
 }
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 450e988..262933d 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -17,12 +17,11 @@
 package com.android.server;
 
 import static android.Manifest.permission.BLUETOOTH_CONNECT;
-import static android.content.PermissionChecker.PERMISSION_HARD_DENIED;
-import static android.content.PermissionChecker.PID_UNKNOWN;
 import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.os.PowerExemptionManager.TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
 import static android.os.UserHandle.USER_SYSTEM;
+import static android.permission.PermissionCheckerManager.PERMISSION_HARD_DENIED;
 
 import android.Manifest;
 import android.annotation.NonNull;
@@ -46,6 +45,7 @@
 import android.bluetooth.IBluetoothManagerCallback;
 import android.bluetooth.IBluetoothProfileServiceConnection;
 import android.bluetooth.IBluetoothStateChangeCallback;
+import android.bluetooth.IBluetoothLeCallControl;
 import android.content.ActivityNotFoundException;
 import android.content.AttributionSource;
 import android.content.BroadcastReceiver;
@@ -54,7 +54,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.PermissionChecker;
 import android.content.ServiceConnection;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
@@ -76,6 +75,7 @@
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.permission.PermissionManager;
 import android.provider.Settings;
 import android.provider.Settings.SettingNotFoundException;
 import android.text.TextUtils;
@@ -110,10 +110,6 @@
     private static final String BLUETOOTH_PRIVILEGED =
             android.Manifest.permission.BLUETOOTH_PRIVILEGED;
 
-    private static final String SECURE_SETTINGS_BLUETOOTH_ADDR_VALID = "bluetooth_addr_valid";
-    private static final String SECURE_SETTINGS_BLUETOOTH_ADDRESS = "bluetooth_address";
-    private static final String SECURE_SETTINGS_BLUETOOTH_NAME = "bluetooth_name";
-
     private static final int ACTIVE_LOG_MAX_SIZE = 20;
     private static final int CRASH_LOG_MAX_SIZE = 100;
 
@@ -641,7 +637,7 @@
         if (mContext.getResources()
                 .getBoolean(com.android.internal.R.bool.config_bluetooth_address_validation)
                 && Settings.Secure.getIntForUser(mContentResolver,
-                SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 0, mUserId)
+                Settings.Secure.BLUETOOTH_NAME, 0, mUserId)
                 == 0) {
             // if the valid flag is not set, don't load the address and name
             if (DBG) {
@@ -650,9 +646,9 @@
             return;
         }
         mName = Settings.Secure.getStringForUser(
-                mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME, mUserId);
+                mContentResolver, Settings.Secure.BLUETOOTH_NAME, mUserId);
         mAddress = Settings.Secure.getStringForUser(
-                mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS, mUserId);
+                mContentResolver, Settings.Secure.BLUETOOTH_ADDRESS, mUserId);
         if (DBG) {
             Slog.d(TAG, "Stored bluetooth Name=" + mName + ",Address=" + mAddress);
         }
@@ -666,30 +662,30 @@
      */
     private void storeNameAndAddress(String name, String address) {
         if (name != null) {
-            Settings.Secure.putStringForUser(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME, name,
+            Settings.Secure.putStringForUser(mContentResolver, Settings.Secure.BLUETOOTH_NAME, name,
                     mUserId);
             mName = name;
             if (DBG) {
                 Slog.d(TAG, "Stored Bluetooth name: " + Settings.Secure.getStringForUser(
-                        mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME,
+                        mContentResolver, Settings.Secure.BLUETOOTH_NAME,
                         mUserId));
             }
         }
 
         if (address != null) {
-            Settings.Secure.putStringForUser(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS,
+            Settings.Secure.putStringForUser(mContentResolver, Settings.Secure.BLUETOOTH_ADDRESS,
                     address, mUserId);
             mAddress = address;
             if (DBG) {
                 Slog.d(TAG,
                         "Stored Bluetoothaddress: " + Settings.Secure.getStringForUser(
-                                mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS,
+                                mContentResolver, Settings.Secure.BLUETOOTH_ADDRESS,
                                 mUserId));
             }
         }
 
         if ((name != null) && (address != null)) {
-            Settings.Secure.putIntForUser(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 1,
+            Settings.Secure.putIntForUser(mContentResolver, Settings.Secure.BLUETOOTH_ADDR_VALID, 1,
                     mUserId);
         }
     }
@@ -1328,11 +1324,15 @@
                             + bluetoothProfile);
                 }
 
-                if (bluetoothProfile != BluetoothProfile.HEADSET) {
+                Intent intent;
+                if (bluetoothProfile == BluetoothProfile.HEADSET) {
+                    intent = new Intent(IBluetoothHeadset.class.getName());
+                } else if (bluetoothProfile== BluetoothProfile.LE_CALL_CONTROL) {
+                    intent = new Intent(IBluetoothLeCallControl.class.getName());
+                } else {
                     return false;
                 }
 
-                Intent intent = new Intent(IBluetoothHeadset.class.getName());
                 psc = new ProfileServiceConnections(intent);
                 if (!psc.bindService()) {
                     return false;
@@ -2912,9 +2912,16 @@
     @SuppressLint("AndroidFrameworkRequiresPermission")
     private static boolean checkPermissionForDataDelivery(Context context, String permission,
             AttributionSource attributionSource, String message) {
-        final int result = PermissionChecker.checkPermissionForDataDeliveryFromDataSource(
-                context, permission, PID_UNKNOWN,
-                new AttributionSource(context.getAttributionSource(), attributionSource), message);
+        PermissionManager pm = context.getSystemService(PermissionManager.class);
+        if (pm == null) {
+            return false;
+        }
+        AttributionSource currentAttribution = new AttributionSource
+                .Builder(context.getAttributionSource())
+                .setNext(attributionSource)
+                .build();
+        final int result = pm.checkPermissionForDataDeliveryFromDataSource(permission,
+                currentAttribution, message);
         if (result == PERMISSION_GRANTED) {
             return true;
         }
diff --git a/services/core/java/com/android/server/ConsumerIrService.java b/services/core/java/com/android/server/ConsumerIrService.java
index 2ed6c77..c4e84a4 100644
--- a/services/core/java/com/android/server/ConsumerIrService.java
+++ b/services/core/java/com/android/server/ConsumerIrService.java
@@ -19,17 +19,19 @@
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.hardware.IConsumerIrService;
+import android.hardware.ir.ConsumerIrFreqRange;
+import android.hardware.ir.IConsumerIr;
 import android.os.PowerManager;
+import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.util.Slog;
 
-import java.lang.RuntimeException;
-
 public class ConsumerIrService extends IConsumerIrService.Stub {
     private static final String TAG = "ConsumerIrService";
 
     private static final int MAX_XMIT_TIME = 2000000; /* in microseconds */
 
-    private static native boolean halOpen();
+    private static native boolean getHidlHalService();
     private static native int halTransmit(int carrierFrequency, int[] pattern);
     private static native int[] halGetCarrierFrequencies();
 
@@ -37,6 +39,7 @@
     private final PowerManager.WakeLock mWakeLock;
     private final boolean mHasNativeHal;
     private final Object mHalLock = new Object();
+    private IConsumerIr mAidlService = null;
 
     ConsumerIrService(Context context) {
         mContext = context;
@@ -45,7 +48,8 @@
         mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
         mWakeLock.setReferenceCounted(true);
 
-        mHasNativeHal = halOpen();
+        mHasNativeHal = getHalService();
+
         if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CONSUMER_IR)) {
             if (!mHasNativeHal) {
                 throw new RuntimeException("FEATURE_CONSUMER_IR present, but no IR HAL loaded!");
@@ -60,6 +64,19 @@
         return mHasNativeHal;
     }
 
+    private boolean getHalService() {
+        // Attempt to get the AIDL HAL service first
+        final String fqName = IConsumerIr.DESCRIPTOR + "/default";
+        mAidlService = IConsumerIr.Stub.asInterface(
+                        ServiceManager.waitForDeclaredService(fqName));
+        if (mAidlService != null) {
+            return true;
+        }
+
+        // Fall back to the HIDL HAL service
+        return getHidlHalService();
+    }
+
     private void throwIfNoIrEmitter() {
         if (!mHasNativeHal) {
             throw new UnsupportedOperationException("IR emitter not available");
@@ -91,10 +108,18 @@
 
         // Right now there is no mechanism to ensure fair queing of IR requests
         synchronized (mHalLock) {
-            int err = halTransmit(carrierFrequency, pattern);
+            if (mAidlService != null) {
+                try {
+                    mAidlService.transmit(carrierFrequency, pattern);
+                } catch (RemoteException ignore) {
+                    Slog.e(TAG, "Error transmitting frequency: " + carrierFrequency);
+                }
+            } else {
+                int err = halTransmit(carrierFrequency, pattern);
 
-            if (err < 0) {
-                Slog.e(TAG, "Error transmitting: " + err);
+                if (err < 0) {
+                    Slog.e(TAG, "Error transmitting: " + err);
+                }
             }
         }
     }
@@ -109,7 +134,24 @@
         throwIfNoIrEmitter();
 
         synchronized(mHalLock) {
-            return halGetCarrierFrequencies();
+            if (mAidlService != null) {
+                try {
+                    ConsumerIrFreqRange[] output = mAidlService.getCarrierFreqs();
+                    if (output.length <= 0) {
+                        Slog.e(TAG, "Error getting carrier frequencies.");
+                    }
+                    int[] result = new int[output.length * 2];
+                    for (int i = 0; i < output.length; i++) {
+                        result[i * 2] = output[i].minHz;
+                        result[i * 2 + 1] = output[i].maxHz;
+                    }
+                    return result;
+                } catch (RemoteException ignore) {
+                    return null;
+                }
+            } else {
+                return halGetCarrierFrequencies();
+            }
         }
     }
 }
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index c7f4b4d..780afd8 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -80,6 +80,7 @@
 import android.database.ContentObserver;
 import android.net.Uri;
 import android.os.Binder;
+import android.os.Build;
 import android.os.DropBoxManager;
 import android.os.Environment;
 import android.os.Handler;
@@ -1648,7 +1649,8 @@
                     // obb data to its new location. This may take time depending on the size of
                     // the data to be copied so it's done on the StorageManager worker thread.
                     // This needs to be finished before start mounting obb directories.
-                    if (userId == 0) {
+                    if (userId == 0
+                            && Build.VERSION.DEVICE_INITIAL_SDK_INT < Build.VERSION_CODES.Q) {
                         mPmInternal.migrateLegacyObbData();
                     }
 
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index f0f6bd1..9d2b4e7 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -189,6 +189,7 @@
 import android.app.PropertyInvalidatedCache;
 import android.app.SyncNotedAppOp;
 import android.app.WaitResult;
+import android.app.WtfException;
 import android.app.backup.BackupManager.OperationType;
 import android.app.backup.IBackupManager;
 import android.app.compat.CompatChanges;
@@ -5822,7 +5823,7 @@
 
         return Arrays.binarySearch(allowlist, appId) >= 0
                 || Arrays.binarySearch(mDeviceIdleTempAllowlist, appId) >= 0
-                || mPendingTempAllowlist.indexOfKey(uid) >= 0;
+                || mPendingTempAllowlist.get(uid) != null;
     }
 
     /**
@@ -12634,6 +12635,7 @@
         int callingUid;
         int callingPid;
         boolean instantApp;
+        boolean throwWtfException = false;
         synchronized(this) {
             if (caller != null) {
                 callerApp = getRecordForAppLOSP(caller);
@@ -12728,13 +12730,9 @@
                                         + "RECEIVER_NOT_EXPORTED be specified when registering a "
                                         + "receiver");
                     } else {
-                        Slog.wtf(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");
+                        // will be removed when enforcement is required
                         // Assume default behavior-- flag check is not enforced
+                        throwWtfException = true;
                         flags |= Context.RECEIVER_EXPORTED;
                     }
                 } else if (!requireExplicitFlagForDynamicReceivers) {
@@ -12865,6 +12863,15 @@
                 }
             }
 
+            if (throwWtfException) {
+                throw new WtfException(
+                        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");
+            }
+
             return sticky;
         }
     }
@@ -15115,11 +15122,13 @@
 
         // First copy out the pending changes...  we need to leave them in the map for now,
         // in case someone needs to check what is coming up while we don't have the lock held.
-        synchronized (mProcLock) {
-            N = mPendingTempAllowlist.size();
-            list = new PendingTempAllowlist[N];
-            for (int i = 0; i < N; i++) {
-                list[i] = mPendingTempAllowlist.valueAt(i);
+        synchronized (this) {
+            synchronized (mProcLock) {
+                N = mPendingTempAllowlist.size();
+                list = new PendingTempAllowlist[N];
+                for (int i = 0; i < N; i++) {
+                    list[i] = mPendingTempAllowlist.valueAt(i);
+                }
             }
         }
 
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 5fc11e8..8cb2040 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -56,6 +56,7 @@
 import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.UserHandle;
+import android.os.WakeLockStats;
 import android.os.WorkSource;
 import android.os.connectivity.CellularBatteryStats;
 import android.os.connectivity.GpsBatteryStats;
@@ -2596,6 +2597,20 @@
     }
 
     /**
+     * Gets a snapshot of wake lock stats
+     * @hide
+     */
+    public WakeLockStats getWakeLockStats() {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BATTERY_STATS, null);
+
+        // Wait for the completion of pending works if there is any
+        awaitCompletion();
+        synchronized (mStats) {
+            return mStats.getWakeLockStats();
+        }
+    }
+
+    /**
      * Gets a snapshot of the system health for a particular uid.
      */
     @Override
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 91d6488..2ec4a02 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -632,6 +632,12 @@
     private void deliverToRegisteredReceiverLocked(BroadcastRecord r,
             BroadcastFilter filter, boolean ordered, int index) {
         boolean skip = false;
+        if (r.options != null && !r.options.testRequireCompatChange(filter.owningUid)) {
+            Slog.w(TAG, "Compat change filtered: broadcasting " + r.intent.toString()
+                    + " to uid " + filter.owningUid + " due to compat change "
+                    + r.options.getRequireCompatChangeId());
+            skip = true;
+        }
         if (!mService.validateAssociationAllowedLocked(r.callerPackage, r.callingUid,
                 filter.packageName, filter.owningUid)) {
             Slog.w(TAG, "Association not allowed: broadcasting "
@@ -1407,6 +1413,13 @@
                     + "] broadcasting " + broadcastDescription(r, component));
             skip = true;
         }
+        if (brOptions != null &&
+                !brOptions.testRequireCompatChange(info.activityInfo.applicationInfo.uid)) {
+            Slog.w(TAG, "Compat change filtered: broadcasting " + broadcastDescription(r, component)
+                    + " to uid " + info.activityInfo.applicationInfo.uid + " due to compat change "
+                    + r.options.getRequireCompatChangeId());
+            skip = true;
+        }
         if (!skip && !mService.validateAssociationAllowedLocked(r.callerPackage, r.callingUid,
                 component.getPackageName(), info.activityInfo.applicationInfo.uid)) {
             Slog.w(TAG, "Association not allowed: broadcasting "
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index 0c94fbb..c55bbe8 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -920,7 +920,7 @@
     void unfreezeTemporarily(ProcessRecord app) {
         if (mUseFreezer) {
             synchronized (mProcLock) {
-                if (app.mOptRecord.isFrozen()) {
+                if (app.mOptRecord.isFrozen() || app.mOptRecord.isPendingFreeze()) {
                     unfreezeAppLSP(app);
                     freezeAppAsyncLSP(app);
                 }
diff --git a/services/core/java/com/android/server/am/OomAdjuster.md b/services/core/java/com/android/server/am/OomAdjuster.md
index eda511a..febc37b 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.md
+++ b/services/core/java/com/android/server/am/OomAdjuster.md
@@ -59,6 +59,7 @@
       * The next two factors are either it was the previous process with visible UI to the user, or it's a backup agent.
       * And then it goes to the massive searches against the service connections and the content providers, each of the clients will be evaluated, and the Oom Adj score could get updated according to its clients' scores. However there are a bunch of service binding flags which could impact the result:
         * Below table captures the results with given various service binding states:
+
         | Conditon #1                     | Condition #2                                               | Condition #3                                 | Condition #4                                      | Result                   |
         |---------------------------------|------------------------------------------------------------|----------------------------------------------|---------------------------------------------------|--------------------------|
         | `BIND_WAIVE_PRIORITY` not set   | `BIND_ALLOW_OOM_MANAGEMENT` set                            | Shown UI && Not Home                         |                                                   | Use the app's own Adj    |
@@ -83,6 +84,7 @@
         |                                 |                                                            | `BIND_NOT_FOREGROUND` not set                | `BIND_IMPORTANT` is set                           | Sched = top app bound    |
         |                                 |                                                            |                                              | `BIND_IMPORTANT` is NOT set                       | Sched = default          |
         * Below table captures the results with given various content provider binding states:
+
         | Conditon #1                     | Condition #2                                               | Condition #3                                 | Result                   |
         |---------------------------------|------------------------------------------------------------|----------------------------------------------|--------------------------|
         | Client's process state >= cached|                                                            |                                              | Client ProcState = empty |
@@ -95,6 +97,7 @@
         | Still within retain time        | Adj > previous app Adj                                     |                                              | adj = previuos app adj   |
         |                                 | Process state > last activity                              |                                              | ProcState = last activity|
         * Some additional tweaks after the above ones:
+
         | Conditon #1                     | Condition #2                                               | Condition #3                                 | Result                             |
         |---------------------------------|------------------------------------------------------------|----------------------------------------------|------------------------------------|
         | Process state >= cached empty   | Has client activities                                      |                                              | ProcState = cached activity client |
diff --git a/services/core/java/com/android/server/am/PendingTempAllowlists.java b/services/core/java/com/android/server/am/PendingTempAllowlists.java
index 75935c4..0263de7 100644
--- a/services/core/java/com/android/server/am/PendingTempAllowlists.java
+++ b/services/core/java/com/android/server/am/PendingTempAllowlists.java
@@ -16,6 +16,8 @@
 
 package com.android.server.am;
 
+import static android.os.Process.INVALID_UID;
+
 import android.util.SparseArray;
 
 /** Allowlists of uids to temporarily bypass Power Save mode. */
@@ -31,29 +33,42 @@
     }
 
     void put(int uid, ActivityManagerService.PendingTempAllowlist value) {
-        mPendingTempAllowlist.put(uid, value);
+        synchronized (mPendingTempAllowlist) {
+            mPendingTempAllowlist.put(uid, value);
+        }
         mService.mAtmInternal.onUidAddedToPendingTempAllowlist(uid, value.tag);
     }
 
     void removeAt(int index) {
-        final int uid = mPendingTempAllowlist.keyAt(index);
-        mPendingTempAllowlist.removeAt(index);
+        int uid = INVALID_UID;
+        synchronized (mPendingTempAllowlist) {
+            uid = mPendingTempAllowlist.keyAt(index);
+            mPendingTempAllowlist.removeAt(index);
+        }
         mService.mAtmInternal.onUidRemovedFromPendingTempAllowlist(uid);
     }
 
     ActivityManagerService.PendingTempAllowlist get(int uid) {
-        return mPendingTempAllowlist.get(uid);
+        synchronized (mPendingTempAllowlist) {
+            return mPendingTempAllowlist.get(uid);
+        }
     }
 
     int size() {
-        return mPendingTempAllowlist.size();
+        synchronized (mPendingTempAllowlist) {
+            return mPendingTempAllowlist.size();
+        }
     }
 
     ActivityManagerService.PendingTempAllowlist valueAt(int index) {
-        return mPendingTempAllowlist.valueAt(index);
+        synchronized (mPendingTempAllowlist) {
+            return mPendingTempAllowlist.valueAt(index);
+        }
     }
 
     int indexOfKey(int key) {
-        return mPendingTempAllowlist.indexOfKey(key);
+        synchronized (mPendingTempAllowlist) {
+            return mPendingTempAllowlist.indexOfKey(key);
+        }
     }
 }
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 2def50e..1ad0bce 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -135,6 +135,7 @@
 import com.android.server.am.ActivityManagerService.ProcessChangeItem;
 import com.android.server.compat.PlatformCompat;
 import com.android.server.pm.dex.DexManager;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.wm.ActivityServiceConnectionsHolder;
 import com.android.server.wm.WindowManagerService;
@@ -2379,6 +2380,8 @@
             final String[] targetPackagesList = sharedPackages.length == 0
                     ? new String[]{app.info.packageName} : sharedPackages;
 
+            final boolean hasAppStorage = hasAppStorage(pmInt, app.info.packageName);
+
             pkgDataInfoMap = getPackageAppDataInfoMap(pmInt, targetPackagesList, uid);
             if (pkgDataInfoMap == null) {
                 // TODO(b/152760674): Handle inode == 0 case properly, now we just give it a
@@ -2401,6 +2404,12 @@
                 bindMountAppsData = false;
             }
 
+            if (!hasAppStorage) {
+                bindMountAppsData = false;
+                pkgDataInfoMap = null;
+                allowlistedAppDataInfoMap = null;
+            }
+
             int userId = UserHandle.getUserId(uid);
             StorageManagerInternal storageManagerInternal = LocalServices.getService(
                     StorageManagerInternal.class);
@@ -2488,6 +2497,17 @@
         }
     }
 
+    private boolean hasAppStorage(PackageManagerInternal pmInt, String packageName) {
+        final AndroidPackage pkg = pmInt.getPackage(packageName);
+        if (pkg == null) {
+            Slog.w(TAG, "Unknown package " + packageName);
+            return false;
+        }
+        final PackageManager.Property noAppStorageProp =
+                    pkg.getProperties().get(PackageManager.PROPERTY_NO_APP_DATA_STORAGE);
+        return noAppStorageProp == null || !noAppStorageProp.getBoolean();
+    }
+
     @GuardedBy("mService")
     void startProcessLocked(ProcessRecord app, HostingRecord hostingRecord, int zygotePolicyFlags) {
         startProcessLocked(app, hostingRecord, zygotePolicyFlags, null /* abiOverride */);
diff --git a/services/core/java/com/android/server/app/GameClassifier.java b/services/core/java/com/android/server/app/GameClassifier.java
new file mode 100644
index 0000000..e20bf46
--- /dev/null
+++ b/services/core/java/com/android/server/app/GameClassifier.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.app;
+
+import android.annotation.NonNull;
+import android.os.UserHandle;
+
+/**
+ * Responsible for determining if a given application is a game.
+ */
+interface GameClassifier {
+
+    /**
+     * Returns {@code true} if the application associated with the given {@code packageName} is
+     * considered to be a game. The application is queried as the user associated with the given
+     * {@code userHandle}.
+     */
+    boolean isGame(@NonNull String packageName, @NonNull UserHandle userHandle);
+}
diff --git a/services/core/java/com/android/server/app/GameClassifierImpl.java b/services/core/java/com/android/server/app/GameClassifierImpl.java
new file mode 100644
index 0000000..8f5b0f0
--- /dev/null
+++ b/services/core/java/com/android/server/app/GameClassifierImpl.java
@@ -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 com.android.server.app;
+
+import android.annotation.NonNull;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.os.UserHandle;
+
+final class GameClassifierImpl implements GameClassifier {
+
+    private final PackageManager mPackageManager;
+
+    GameClassifierImpl(@NonNull PackageManager packageManager) {
+        mPackageManager = packageManager;
+    }
+
+    @Override
+    public boolean isGame(@NonNull String packageName, @NonNull UserHandle userHandle) {
+        @ApplicationInfo.Category
+        int applicationCategory = ApplicationInfo.CATEGORY_UNDEFINED;
+
+        try {
+            applicationCategory =
+                    mPackageManager.getApplicationInfoAsUser(
+                            packageName,
+                            0,
+                            userHandle.getIdentifier()).category;
+        } catch (PackageManager.NameNotFoundException ex) {
+            return false;
+        }
+
+        return applicationCategory == ApplicationInfo.CATEGORY_GAME;
+    }
+}
diff --git a/services/core/java/com/android/server/app/GameManagerService.java b/services/core/java/com/android/server/app/GameManagerService.java
index fc48cd5..0980f40 100644
--- a/services/core/java/com/android/server/app/GameManagerService.java
+++ b/services/core/java/com/android/server/app/GameManagerService.java
@@ -76,6 +76,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.compat.CompatibilityOverrideConfig;
 import com.android.internal.compat.IPlatformCompat;
+import com.android.internal.os.BackgroundThread;
 import com.android.server.LocalServices;
 import com.android.server.ServiceThread;
 import com.android.server.SystemService;
@@ -563,7 +564,12 @@
             mService.registerPackageReceiver();
 
             if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_GAME_SERVICE)) {
-                mGameServiceController = new GameServiceController(context);
+                mGameServiceController = new GameServiceController(
+                        BackgroundThread.getExecutor(),
+                        new GameServiceProviderSelectorImpl(
+                                getContext().getResources(),
+                                getContext().getPackageManager()),
+                        new GameServiceProviderInstanceFactoryImpl(getContext()));
             }
         }
 
@@ -586,6 +592,14 @@
         }
 
         @Override
+        public void onUserUnlocking(@NonNull TargetUser user) {
+            super.onUserUnlocking(user);
+            if (mGameServiceController != null) {
+                mGameServiceController.notifyUserUnlocking(user);
+            }
+        }
+
+        @Override
         public void onUserStopping(@NonNull TargetUser user) {
             mService.onUserStopping(user.getUserIdentifier());
             if (mGameServiceController != null) {
diff --git a/services/core/java/com/android/server/app/GameServiceConnection.java b/services/core/java/com/android/server/app/GameServiceConnection.java
deleted file mode 100644
index b607789..0000000
--- a/services/core/java/com/android/server/app/GameServiceConnection.java
+++ /dev/null
@@ -1,102 +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.app;
-
-import android.annotation.Nullable;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.service.games.GameService;
-import android.service.games.IGameService;
-import android.util.Slog;
-
-final class GameServiceConnection {
-    private static final String TAG = "GameServiceConnection";
-    private static final boolean DEBUG = false;
-
-    private final Context mContext;
-    private final ComponentName mGameServiceComponent;
-    private final int mUser;
-    private boolean mIsBound;
-    @Nullable
-    private IGameService mGameService;
-    private final ServiceConnection mConnection = new ServiceConnection() {
-        @Override
-        public void onServiceConnected(ComponentName name, IBinder service) {
-            if (DEBUG) {
-                Slog.d(TAG, "onServiceConnected to " + name + " for user(" + mUser + ")");
-            }
-
-            mGameService = IGameService.Stub.asInterface(service);
-            try {
-                mGameService.connected();
-            } catch (RemoteException e) {
-                Slog.w(TAG, "RemoteException while calling ready", e);
-            }
-        }
-
-        @Override
-        public void onServiceDisconnected(ComponentName name) {
-            if (DEBUG) {
-                Slog.d(TAG, "onServiceDisconnected to " + name);
-            }
-
-            mGameService = null;
-        }
-    };
-
-    GameServiceConnection(Context context, ComponentName gameServiceComponent, int user) {
-        mContext = context;
-        mGameServiceComponent = gameServiceComponent;
-        mUser = user;
-    }
-
-    public void connect() {
-        if (mIsBound) {
-            Slog.v(TAG, "Already bound, ignoring start.");
-            return;
-        }
-
-        Intent intent = new Intent(GameService.SERVICE_INTERFACE);
-        intent.setComponent(mGameServiceComponent);
-        mIsBound = mContext.bindServiceAsUser(intent, mConnection,
-                Context.BIND_AUTO_CREATE
-                        | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS, new UserHandle(mUser));
-        if (!mIsBound) {
-            Slog.w(TAG, "Failed binding to game service " + mGameServiceComponent);
-        }
-    }
-
-    public void disconnect() {
-        try {
-            if (mGameService != null) {
-                mGameService.disconnected();
-            }
-        } catch (RemoteException e) {
-            Slog.w(TAG, "RemoteException in shutdown", e);
-        }
-
-        if (mIsBound) {
-            mContext.unbindService(mConnection);
-            mIsBound = false;
-        }
-    }
-}
diff --git a/services/core/java/com/android/server/app/GameServiceController.java b/services/core/java/com/android/server/app/GameServiceController.java
index d056ea9..ac720b9 100644
--- a/services/core/java/com/android/server/app/GameServiceController.java
+++ b/services/core/java/com/android/server/app/GameServiceController.java
@@ -18,40 +18,56 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
-import android.service.games.GameService;
-import android.text.TextUtils;
+import android.annotation.WorkerThread;
 import android.util.Slog;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.server.SystemService;
 
-import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.Executor;
 
+/**
+ * Responsible for managing the Game Service API.
+ *
+ * Key responsibilities selecting the active Game Service provider, binding to the Game Service
+ * provider services, and driving the GameService/GameSession lifecycles.
+ */
 final class GameServiceController {
     private static final String TAG = "GameServiceController";
-    private static final boolean DEBUG = false;
 
-    private final Context mContext;
+
+    private final Object mLock = new Object();
+    private final Executor mBackgroundExecutor;
+    private final GameServiceProviderSelector mGameServiceProviderSelector;
+    private final GameServiceProviderInstanceFactory mGameServiceProviderInstanceFactory;
+
+    private volatile boolean mHasBootCompleted;
     @Nullable
-    private SystemService.TargetUser mCurrentForegroundUser;
-    private boolean mHasBootCompleted;
-
+    private volatile SystemService.TargetUser mCurrentForegroundUser;
+    @GuardedBy("mLock")
     @Nullable
-    private GameServiceConnection mGameServiceConnection;
+    private volatile GameServiceProviderConfiguration mActiveGameServiceProviderConfiguration;
+    @GuardedBy("mLock")
+    @Nullable
+    private volatile GameServiceProviderInstance mGameServiceProviderInstance;
 
-    GameServiceController(Context context) {
-        mContext = context;
+    GameServiceController(
+            @NonNull Executor backgroundExecutor,
+            @NonNull GameServiceProviderSelector gameServiceProviderSelector,
+            @NonNull GameServiceProviderInstanceFactory gameServiceProviderInstanceFactory) {
+        mGameServiceProviderInstanceFactory = gameServiceProviderInstanceFactory;
+        mBackgroundExecutor = backgroundExecutor;
+        mGameServiceProviderSelector = gameServiceProviderSelector;
     }
 
     void onBootComplete() {
+        if (mHasBootCompleted) {
+            return;
+        }
         mHasBootCompleted = true;
 
-        evaluateGameServiceConnection();
+        mBackgroundExecutor.execute(this::evaluateActiveGameServiceProvider);
     }
 
     void notifyUserStarted(@NonNull SystemService.TargetUser user) {
@@ -59,96 +75,86 @@
             return;
         }
 
-        mCurrentForegroundUser = user;
-        evaluateGameServiceConnection();
+        setCurrentForegroundUserAndEvaluateProvider(user);
     }
 
     void notifyNewForegroundUser(@NonNull SystemService.TargetUser user) {
-        mCurrentForegroundUser = user;
-        evaluateGameServiceConnection();
+        setCurrentForegroundUserAndEvaluateProvider(user);
     }
 
-    void notifyUserStopped(@NonNull SystemService.TargetUser user) {
-        if (mCurrentForegroundUser == null
-                || mCurrentForegroundUser.getUserIdentifier() != user.getUserIdentifier()) {
+    void notifyUserUnlocking(@NonNull SystemService.TargetUser user) {
+        boolean isSameAsForegroundUser =
+                mCurrentForegroundUser != null
+                        && mCurrentForegroundUser.getUserIdentifier() == user.getUserIdentifier();
+        if (!isSameAsForegroundUser) {
             return;
         }
 
-        mCurrentForegroundUser = null;
-        evaluateGameServiceConnection();
+        // It is likely that the Game Service provider's components are not Direct Boot mode aware
+        // and will not be capable of running until the user has unlocked the device. To allow for
+        // this we re-evaluate the active game service provider once these components are available.
+
+        mBackgroundExecutor.execute(this::evaluateActiveGameServiceProvider);
     }
 
-    private void evaluateGameServiceConnection() {
+    void notifyUserStopped(@NonNull SystemService.TargetUser user) {
+        boolean isSameAsForegroundUser =
+                mCurrentForegroundUser != null
+                        && mCurrentForegroundUser.getUserIdentifier() == user.getUserIdentifier();
+        if (!isSameAsForegroundUser) {
+            return;
+        }
+
+        setCurrentForegroundUserAndEvaluateProvider(null);
+    }
+
+    private void setCurrentForegroundUserAndEvaluateProvider(
+            @Nullable SystemService.TargetUser user) {
+        boolean hasUserChanged =
+                !Objects.equals(mCurrentForegroundUser, user);
+        if (!hasUserChanged) {
+            return;
+        }
+        mCurrentForegroundUser = user;
+
+        mBackgroundExecutor.execute(this::evaluateActiveGameServiceProvider);
+    }
+
+    @WorkerThread
+    private void evaluateActiveGameServiceProvider() {
         if (!mHasBootCompleted) {
             return;
         }
 
-        // TODO(b/204565942): Only shutdown the existing service connection if the game service
-        // provider or user has changed.
-        if (mGameServiceConnection != null) {
-            mGameServiceConnection.disconnect();
-            mGameServiceConnection = null;
-        }
+        synchronized (mLock) {
+            GameServiceProviderConfiguration selectedGameServiceProviderConfiguration =
+                    mGameServiceProviderSelector.get(mCurrentForegroundUser);
 
-        boolean isUserSupported =
-                mCurrentForegroundUser != null
-                        && mCurrentForegroundUser.isFull()
-                        && !mCurrentForegroundUser.isManagedProfile();
-        if (!isUserSupported) {
-            if (DEBUG && mCurrentForegroundUser != null) {
-                Slog.d(TAG, "User not supported: " + mCurrentForegroundUser);
+            boolean didActiveGameServiceProviderChanged =
+                    !Objects.equals(selectedGameServiceProviderConfiguration,
+                            mActiveGameServiceProviderConfiguration);
+            if (!didActiveGameServiceProviderChanged) {
+                return;
             }
-            return;
-        }
 
-        ComponentName gameServiceComponentName =
-                determineGameServiceComponentName(mCurrentForegroundUser.getUserIdentifier());
-        if (gameServiceComponentName == null) {
-            return;
-        }
-
-        mGameServiceConnection = new GameServiceConnection(
-                mContext,
-                gameServiceComponentName,
-                mCurrentForegroundUser.getUserIdentifier());
-        mGameServiceConnection.connect();
-    }
-
-    @Nullable
-    private ComponentName determineGameServiceComponentName(int userId) {
-        String gameServicePackage =
-                mContext.getResources().getString(
-                        com.android.internal.R.string.config_systemGameService);
-        if (TextUtils.isEmpty(gameServicePackage)) {
-            if (DEBUG) {
-                Slog.d(TAG, "No game service package defined");
+            if (mGameServiceProviderInstance != null) {
+                Slog.i(TAG, "Stopping Game Service provider: "
+                        + mActiveGameServiceProviderConfiguration);
+                mGameServiceProviderInstance.stop();
             }
-            return null;
-        }
 
-        List<ResolveInfo> gameServiceResolveInfos =
-                mContext.getPackageManager().queryIntentServicesAsUser(
-                        new Intent(GameService.SERVICE_INTERFACE).setPackage(gameServicePackage),
-                        PackageManager.MATCH_SYSTEM_ONLY,
-                        userId);
+            mActiveGameServiceProviderConfiguration = selectedGameServiceProviderConfiguration;
 
-        if (gameServiceResolveInfos.isEmpty()) {
-            Slog.v(TAG, "No available game service found for user id: " + userId);
-            return null;
-        }
-
-        for (ResolveInfo resolveInfo : gameServiceResolveInfos) {
-            if (resolveInfo.serviceInfo == null) {
-                continue;
+            if (mActiveGameServiceProviderConfiguration == null) {
+                return;
             }
-            final ServiceInfo serviceInfo = resolveInfo.serviceInfo;
-            if (!serviceInfo.isEnabled()) {
-                continue;
-            }
-            return serviceInfo.getComponentName();
-        }
 
-        Slog.v(TAG, "No game service found for user id: " + userId);
-        return null;
+            Slog.i(TAG,
+                    "Starting Game Service provider: " + mActiveGameServiceProviderConfiguration);
+            mGameServiceProviderInstance =
+                    mGameServiceProviderInstanceFactory.create(
+                            mActiveGameServiceProviderConfiguration);
+            mGameServiceProviderInstance.start();
+        }
     }
 }
diff --git a/services/core/java/com/android/server/app/GameServiceProviderConfiguration.java b/services/core/java/com/android/server/app/GameServiceProviderConfiguration.java
new file mode 100644
index 0000000..7c8f251
--- /dev/null
+++ b/services/core/java/com/android/server/app/GameServiceProviderConfiguration.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.app;
+
+import android.annotation.NonNull;
+import android.content.ComponentName;
+import android.os.UserHandle;
+
+import java.util.Objects;
+
+/**
+ * Representation of a {@link android.service.games.GameService} provider configuration.
+ */
+final class GameServiceProviderConfiguration {
+    private final UserHandle mUserHandle;
+    private final ComponentName mGameServiceComponentName;
+    private final ComponentName mGameSessionServiceComponentName;
+
+    GameServiceProviderConfiguration(
+            @NonNull UserHandle userHandle,
+            @NonNull ComponentName gameServiceComponentName,
+            @NonNull ComponentName gameSessionServiceComponentName) {
+        Objects.requireNonNull(userHandle);
+        Objects.requireNonNull(gameServiceComponentName);
+        Objects.requireNonNull(gameSessionServiceComponentName);
+
+        this.mUserHandle = userHandle;
+        this.mGameServiceComponentName = gameServiceComponentName;
+        this.mGameSessionServiceComponentName = gameSessionServiceComponentName;
+    }
+
+    @NonNull
+    public UserHandle getUserHandle() {
+        return mUserHandle;
+    }
+
+    @NonNull
+    public ComponentName getGameServiceComponentName() {
+        return mGameServiceComponentName;
+    }
+
+    @NonNull
+    public ComponentName getGameSessionServiceComponentName() {
+        return mGameSessionServiceComponentName;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+
+        if (!(o instanceof GameServiceProviderConfiguration)) {
+            return false;
+        }
+
+        GameServiceProviderConfiguration that = (GameServiceProviderConfiguration) o;
+        return mUserHandle.equals(that.mUserHandle)
+                && mGameServiceComponentName.equals(that.mGameServiceComponentName)
+                && mGameSessionServiceComponentName.equals(that.mGameSessionServiceComponentName);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mUserHandle, mGameServiceComponentName,
+                mGameSessionServiceComponentName);
+    }
+
+    @Override
+    public String toString() {
+        return "GameServiceProviderConfiguration{"
+                + "mUserHandle="
+                + mUserHandle
+                + ", gameServiceComponentName="
+                + mGameServiceComponentName
+                + ", gameSessionServiceComponentName="
+                + mGameSessionServiceComponentName
+                + '}';
+    }
+}
diff --git a/services/core/java/com/android/server/app/GameServiceProviderInstance.java b/services/core/java/com/android/server/app/GameServiceProviderInstance.java
new file mode 100644
index 0000000..e83f9ac
--- /dev/null
+++ b/services/core/java/com/android/server/app/GameServiceProviderInstance.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.app;
+
+/**
+ * Representation of an instance of a Game Service provider.
+ *
+ * This includes maintaining the bindings and driving the interactions with the provider's
+ * implementations of {@link android.service.games.GameService} and
+ * {@link android.service.games.GameSessionService}.
+ */
+interface GameServiceProviderInstance {
+    /**
+     * Begins running the Game Service provider instance.
+     */
+    void start();
+
+    /**
+     * Stops running the Game Service provider instance.
+     */
+    void stop();
+}
diff --git a/telephony/java/com/android/internal/telephony/euicc/IResultCallback.aidl b/services/core/java/com/android/server/app/GameServiceProviderInstanceFactory.java
similarity index 65%
copy from telephony/java/com/android/internal/telephony/euicc/IResultCallback.aidl
copy to services/core/java/com/android/server/app/GameServiceProviderInstanceFactory.java
index 69f479c..7640cc5 100644
--- a/telephony/java/com/android/internal/telephony/euicc/IResultCallback.aidl
+++ b/services/core/java/com/android/server/app/GameServiceProviderInstanceFactory.java
@@ -13,11 +13,17 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.internal.telephony.euicc;
 
-import android.content.Intent;
+package com.android.server.app;
 
-/** @hide */
-oneway interface IResultCallback {
-    void onComplete(int resultCode, in Intent resultIntent);
+import android.annotation.NonNull;
+
+/**
+ * Factory for creating {@link GameServiceProviderInstance}.
+ */
+interface GameServiceProviderInstanceFactory {
+
+    @NonNull
+    GameServiceProviderInstance create(@NonNull
+            GameServiceProviderConfiguration gameServiceProviderConfiguration);
 }
diff --git a/services/core/java/com/android/server/app/GameServiceProviderInstanceFactoryImpl.java b/services/core/java/com/android/server/app/GameServiceProviderInstanceFactoryImpl.java
new file mode 100644
index 0000000..d5ac03a
--- /dev/null
+++ b/services/core/java/com/android/server/app/GameServiceProviderInstanceFactoryImpl.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.server.app;
+
+import android.annotation.NonNull;
+import android.app.ActivityTaskManager;
+import android.content.Context;
+import android.content.Intent;
+import android.service.games.GameService;
+import android.service.games.GameSessionService;
+import android.service.games.IGameService;
+import android.service.games.IGameSessionService;
+
+import com.android.internal.infra.ServiceConnector;
+import com.android.internal.os.BackgroundThread;
+
+final class GameServiceProviderInstanceFactoryImpl implements GameServiceProviderInstanceFactory {
+    private final Context mContext;
+
+    GameServiceProviderInstanceFactoryImpl(@NonNull Context context) {
+        this.mContext = context;
+    }
+
+    @NonNull
+    @Override
+    public GameServiceProviderInstance create(@NonNull
+            GameServiceProviderConfiguration gameServiceProviderConfiguration) {
+        return new GameServiceProviderInstanceImpl(
+                gameServiceProviderConfiguration.getUserHandle(),
+                BackgroundThread.getExecutor(),
+                new GameClassifierImpl(mContext.getPackageManager()),
+                ActivityTaskManager.getService(),
+                new GameServiceConnector(mContext, gameServiceProviderConfiguration),
+                new GameSessionServiceConnector(mContext, gameServiceProviderConfiguration));
+    }
+
+    private static final class GameServiceConnector extends ServiceConnector.Impl<IGameService> {
+        private static final int DISABLE_AUTOMATIC_DISCONNECT_TIMEOUT = 0;
+        private static final int BINDING_FLAGS = Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS;
+
+        GameServiceConnector(
+                @NonNull Context context,
+                @NonNull GameServiceProviderConfiguration configuration) {
+            super(context, new Intent(GameService.ACTION_GAME_SERVICE)
+                            .setComponent(configuration.getGameServiceComponentName()),
+                    BINDING_FLAGS, configuration.getUserHandle().getIdentifier(),
+                    IGameService.Stub::asInterface);
+        }
+
+        @Override
+        protected long getAutoDisconnectTimeoutMs() {
+            return DISABLE_AUTOMATIC_DISCONNECT_TIMEOUT;
+        }
+    }
+
+    private static final class GameSessionServiceConnector extends
+            ServiceConnector.Impl<IGameSessionService> {
+        private static final int DISABLE_AUTOMATIC_DISCONNECT_TIMEOUT = 0;
+        private static final int BINDING_FLAGS =
+                Context.BIND_TREAT_LIKE_ACTIVITY
+                        | Context.BIND_SCHEDULE_LIKE_TOP_APP
+                        | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS;
+
+        GameSessionServiceConnector(
+                @NonNull Context context,
+                @NonNull GameServiceProviderConfiguration configuration) {
+            super(context, new Intent(GameSessionService.ACTION_GAME_SESSION_SERVICE)
+                            .setComponent(configuration.getGameSessionServiceComponentName()),
+                    BINDING_FLAGS, configuration.getUserHandle().getIdentifier(),
+                    IGameSessionService.Stub::asInterface);
+        }
+
+        @Override
+        protected long getAutoDisconnectTimeoutMs() {
+            return DISABLE_AUTOMATIC_DISCONNECT_TIMEOUT;
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java b/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java
new file mode 100644
index 0000000..3f3f257
--- /dev/null
+++ b/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java
@@ -0,0 +1,294 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.app;
+
+import android.annotation.NonNull;
+import android.app.IActivityTaskManager;
+import android.app.TaskStackListener;
+import android.content.ComponentName;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.service.games.CreateGameSessionRequest;
+import android.service.games.IGameService;
+import android.service.games.IGameSession;
+import android.service.games.IGameSessionService;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.infra.AndroidFuture;
+import com.android.internal.infra.ServiceConnector;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Executor;
+import java.util.concurrent.TimeUnit;
+
+final class GameServiceProviderInstanceImpl implements GameServiceProviderInstance {
+    private static final String TAG = "GameServiceProviderInstance";
+    private static final int CREATE_GAME_SESSION_TIMEOUT_MS = 10_000;
+    private static final boolean DEBUG = false;
+
+    private final TaskStackListener mTaskStackListener = new TaskStackListener() {
+        @Override
+        public void onTaskCreated(int taskId, ComponentName componentName) throws RemoteException {
+            if (componentName == null) {
+                return;
+            }
+
+            mBackgroundExecutor.execute(() -> {
+                GameServiceProviderInstanceImpl.this.onTaskCreated(taskId, componentName);
+            });
+        }
+
+        @Override
+        public void onTaskRemoved(int taskId) throws RemoteException {
+            mBackgroundExecutor.execute(() -> {
+                GameServiceProviderInstanceImpl.this.onTaskRemoved(taskId);
+            });
+        }
+    };
+    private final Object mLock = new Object();
+    private final UserHandle mUserHandle;
+    private final Executor mBackgroundExecutor;
+    private final GameClassifier mGameClassifier;
+    private final IActivityTaskManager mActivityTaskManager;
+    private final ServiceConnector<IGameService> mGameServiceConnector;
+    private final ServiceConnector<IGameSessionService> mGameSessionServiceConnector;
+
+    @GuardedBy("mLock")
+    private final ConcurrentHashMap<Integer, GameSessionRecord> mGameSessions =
+            new ConcurrentHashMap<>();
+    @GuardedBy("mLock")
+    private volatile boolean mIsRunning;
+
+    GameServiceProviderInstanceImpl(
+            UserHandle userHandle,
+            @NonNull Executor backgroundExecutor,
+            @NonNull GameClassifier gameClassifier,
+            @NonNull IActivityTaskManager activityTaskManager,
+            @NonNull ServiceConnector<IGameService> gameServiceConnector,
+            @NonNull ServiceConnector<IGameSessionService> gameSessionServiceConnector) {
+        mUserHandle = userHandle;
+        mBackgroundExecutor = backgroundExecutor;
+        mGameClassifier = gameClassifier;
+        mActivityTaskManager = activityTaskManager;
+        mGameServiceConnector = gameServiceConnector;
+        mGameSessionServiceConnector = gameSessionServiceConnector;
+    }
+
+    @Override
+    public void start() {
+        synchronized (mLock) {
+            startLocked();
+        }
+    }
+
+    @Override
+    public void stop() {
+        synchronized (mLock) {
+            stopLocked();
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void startLocked() {
+        if (mIsRunning) {
+            return;
+        }
+        mIsRunning = true;
+
+        // TODO(b/204503192): In cases where the connection to the game service fails retry with
+        //  back off mechanism.
+        AndroidFuture<Void> unusedPostConnectedFuture = mGameServiceConnector.post(gameService -> {
+            gameService.connected();
+        });
+
+        try {
+            mActivityTaskManager.registerTaskStackListener(mTaskStackListener);
+        } catch (RemoteException e) {
+            Slog.w(TAG, "Failed to register task stack listener", e);
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void stopLocked() {
+        if (!mIsRunning) {
+            return;
+        }
+        mIsRunning = false;
+
+        try {
+            mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
+        } catch (RemoteException e) {
+            Slog.w(TAG, "Failed to unregister task stack listener", e);
+        }
+
+        for (GameSessionRecord gameSessionRecord : mGameSessions.values()) {
+            IGameSession gameSession = gameSessionRecord.getGameSession();
+            if (gameSession == null) {
+                continue;
+            }
+
+            try {
+                gameSession.destroy();
+            } catch (RemoteException ex) {
+                Slog.w(TAG, "Failed to destroy session: " + gameSessionRecord, ex);
+            }
+        }
+        mGameSessions.clear();
+
+        // TODO(b/204503192): It is possible that the game service is disconnected. In this
+        //  case we should avoid rebinding just to shut it down again.
+        AndroidFuture<Void> unusedPostDisconnectedFuture =
+                mGameServiceConnector.post(gameService -> {
+                    gameService.disconnected();
+                });
+        mGameServiceConnector.unbind();
+        mGameSessionServiceConnector.unbind();
+    }
+
+    private void onTaskCreated(int taskId, @NonNull ComponentName componentName) {
+        String packageName = componentName.getPackageName();
+        if (!mGameClassifier.isGame(packageName, mUserHandle)) {
+            return;
+        }
+
+        synchronized (mLock) {
+            createGameSessionLocked(taskId, componentName);
+        }
+    }
+
+    private void onTaskRemoved(int taskId) {
+        synchronized (mLock) {
+            boolean isTaskAssociatedWithGameSession = mGameSessions.containsKey(taskId);
+            if (!isTaskAssociatedWithGameSession) {
+                return;
+            }
+
+            destroyGameSessionLocked(taskId);
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void createGameSessionLocked(int sessionId, @NonNull ComponentName componentName) {
+        if (DEBUG) {
+            Slog.i(TAG, "createGameSession() id: " + sessionId + " component: " + componentName);
+        }
+
+        if (!mIsRunning) {
+            return;
+        }
+
+        GameSessionRecord existingGameSessionRecord = mGameSessions.get(sessionId);
+        if (existingGameSessionRecord != null) {
+            Slog.w(TAG, "Existing game session found for task (id: " + sessionId
+                    + ") creation. Ignoring.");
+            return;
+        }
+
+        GameSessionRecord gameSessionRecord = GameSessionRecord.pendingGameSession(sessionId,
+                componentName);
+        mGameSessions.put(sessionId, gameSessionRecord);
+
+        // TODO(b/207035150): Allow the game service provider to determine if a game session
+        //  should be created. For now we will assume all games should have a session.
+        AndroidFuture<IBinder> gameSessionFuture = new AndroidFuture<IBinder>()
+                .orTimeout(CREATE_GAME_SESSION_TIMEOUT_MS, TimeUnit.MILLISECONDS)
+                .whenCompleteAsync((gameSessionIBinder, exception) -> {
+                    IGameSession gameSession = IGameSession.Stub.asInterface(gameSessionIBinder);
+                    if (exception != null || gameSession == null) {
+                        Slog.w(TAG, "Failed to create GameSession: " + gameSessionRecord,
+                                exception);
+                        synchronized (mLock) {
+                            destroyGameSessionLocked(sessionId);
+                        }
+                        return;
+                    }
+
+                    synchronized (mLock) {
+                        attachGameSessionLocked(sessionId, gameSession);
+                    }
+                }, mBackgroundExecutor);
+
+        AndroidFuture<Void> unusedPostCreateGameSessionFuture =
+                mGameSessionServiceConnector.post(gameService -> {
+                    CreateGameSessionRequest createGameSessionRequest =
+                            new CreateGameSessionRequest(sessionId, componentName.getPackageName());
+                    gameService.create(createGameSessionRequest, gameSessionFuture);
+                });
+    }
+
+    @GuardedBy("mLock")
+    private void attachGameSessionLocked(int sessionId, @NonNull IGameSession gameSession) {
+        if (DEBUG) {
+            Slog.i(TAG, "attachGameSession() id: " + sessionId);
+        }
+
+        GameSessionRecord gameSessionRecord = mGameSessions.get(sessionId);
+        if (gameSessionRecord == null) {
+            Slog.w(TAG, "No associated game session record. Destroying id: " + sessionId);
+
+            try {
+                gameSession.destroy();
+            } catch (RemoteException ex) {
+                Slog.w(TAG, "Failed to destroy session: " + gameSessionRecord, ex);
+            }
+            return;
+        }
+
+        mGameSessions.put(sessionId, gameSessionRecord.withGameSession(gameSession));
+    }
+
+    @GuardedBy("mLock")
+    private void destroyGameSessionLocked(int sessionId) {
+        // TODO(b/204503192): Limit the lifespan of the game session in the Game Service provider
+        // to only when the associated task is running. Right now it is possible for a task to
+        // move into the background and for all associated processes to die and for the Game Session
+        // provider's GameSessionService to continue to be running. Ideally we could unbind the
+        // service when this happens.
+        if (DEBUG) {
+            Slog.i(TAG, "destroyGameSession() id: " + sessionId);
+        }
+
+        GameSessionRecord gameSessionRecord = mGameSessions.remove(sessionId);
+        if (gameSessionRecord == null) {
+            if (DEBUG) {
+                Slog.w(TAG, "No game session found for id: " + sessionId);
+            }
+            return;
+        }
+
+        IGameSession gameSession = gameSessionRecord.getGameSession();
+        if (gameSession != null) {
+            try {
+                gameSession.destroy();
+            } catch (RemoteException ex) {
+                Slog.w(TAG, "Failed to destroy session: " + gameSessionRecord, ex);
+            }
+        }
+
+        if (mGameSessions.isEmpty()) {
+            if (DEBUG) {
+                Slog.i(TAG, "No active game sessions. Disconnecting GameSessionService");
+            }
+
+            if (mGameSessionServiceConnector != null) {
+                mGameSessionServiceConnector.unbind();
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/app/GameServiceProviderSelector.java b/services/core/java/com/android/server/app/GameServiceProviderSelector.java
new file mode 100644
index 0000000..51d3515
--- /dev/null
+++ b/services/core/java/com/android/server/app/GameServiceProviderSelector.java
@@ -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.app;
+
+import android.annotation.Nullable;
+
+import com.android.server.SystemService;
+
+/**
+ * Responsible for determining what the active Game Service provider should be.
+ */
+interface GameServiceProviderSelector {
+
+    /**
+     * Returns the {@link GameServiceProviderConfiguration} associated with the selected Game
+     * Service provider for the given user or {@code null} if none should be used.
+     */
+    @Nullable
+    GameServiceProviderConfiguration get(@Nullable SystemService.TargetUser user);
+}
diff --git a/services/core/java/com/android/server/app/GameServiceProviderSelectorImpl.java b/services/core/java/com/android/server/app/GameServiceProviderSelectorImpl.java
new file mode 100644
index 0000000..54ef707
--- /dev/null
+++ b/services/core/java/com/android/server/app/GameServiceProviderSelectorImpl.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.app;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.os.UserHandle;
+import android.service.games.GameService;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.util.Slog;
+import android.util.Xml;
+
+import com.android.server.SystemService;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.List;
+
+final class GameServiceProviderSelectorImpl implements GameServiceProviderSelector {
+    private static final String TAG = "GameServiceProviderSelector";
+    private static final String GAME_SERVICE_NODE_NAME = "game-service";
+    private static final boolean DEBUG = false;
+
+    private final Resources mResources;
+    private final PackageManager mPackageManager;
+
+    GameServiceProviderSelectorImpl(@NonNull Resources resources,
+            @NonNull PackageManager packageManager) {
+        mResources = resources;
+        mPackageManager = packageManager;
+    }
+
+    @Override
+    @Nullable
+    public GameServiceProviderConfiguration get(@Nullable SystemService.TargetUser user) {
+        if (user == null) {
+            return null;
+        }
+
+        boolean isUserSupported = user.isFull() && !user.isManagedProfile();
+        if (!isUserSupported) {
+            Slog.i(TAG, "Game Service not supported for user: " + user.getUserIdentifier());
+            return null;
+        }
+
+        String gameServicePackage =
+                mResources.getString(
+                        com.android.internal.R.string.config_systemGameService);
+
+        if (TextUtils.isEmpty(gameServicePackage)) {
+            Slog.w(TAG, "No game service package defined");
+            return null;
+        }
+
+        int userId = user.getUserIdentifier();
+        List<ResolveInfo> gameServiceResolveInfos =
+                mPackageManager.queryIntentServicesAsUser(
+                        new Intent(GameService.ACTION_GAME_SERVICE).setPackage(gameServicePackage),
+                        PackageManager.GET_META_DATA | PackageManager.MATCH_SYSTEM_ONLY,
+                        userId);
+        if (DEBUG) {
+            Slog.i(TAG, "Querying package: " + gameServicePackage + " and user id: " + userId);
+            Slog.i(TAG, "Found resolve infos: " + gameServiceResolveInfos);
+        }
+
+        if (gameServiceResolveInfos == null || gameServiceResolveInfos.isEmpty()) {
+            Slog.w(TAG, "No available game service found for user id: " + userId);
+            return null;
+        }
+
+        GameServiceProviderConfiguration selectedProvider = null;
+        for (ResolveInfo resolveInfo : gameServiceResolveInfos) {
+            if (resolveInfo.serviceInfo == null) {
+                continue;
+            }
+            ServiceInfo gameServiceServiceInfo = resolveInfo.serviceInfo;
+
+            ComponentName gameSessionServiceComponentName =
+                    determineGameSessionServiceFromGameService(gameServiceServiceInfo);
+            if (gameSessionServiceComponentName == null) {
+                continue;
+            }
+
+            selectedProvider =
+                    new GameServiceProviderConfiguration(
+                            new UserHandle(userId),
+                            gameServiceServiceInfo.getComponentName(),
+                            gameSessionServiceComponentName);
+            break;
+        }
+
+        if (selectedProvider == null) {
+            Slog.w(TAG, "No valid game service found for user id: " + userId);
+            return null;
+        }
+
+        return selectedProvider;
+    }
+
+    @Nullable
+    private ComponentName determineGameSessionServiceFromGameService(
+            @NonNull ServiceInfo gameServiceServiceInfo) {
+        String gameSessionService;
+        try (XmlResourceParser parser = gameServiceServiceInfo.loadXmlMetaData(mPackageManager,
+                GameService.SERVICE_META_DATA)) {
+            if (parser == null) {
+                Slog.w(TAG, "No " + GameService.SERVICE_META_DATA + " meta-data found for "
+                        + gameServiceServiceInfo.getComponentName());
+                return null;
+            }
+
+            Resources resources = mPackageManager.getResourcesForApplication(
+                    gameServiceServiceInfo.packageName);
+
+            AttributeSet attributeSet = Xml.asAttributeSet(parser);
+            int type;
+            while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                    && type != XmlPullParser.START_TAG) {
+                // Do nothing
+            }
+
+            boolean isStartingTagGameService = GAME_SERVICE_NODE_NAME.equals(parser.getName());
+            if (!isStartingTagGameService) {
+                Slog.w(TAG, "Meta-data does not start with " + GAME_SERVICE_NODE_NAME + " tag");
+                return null;
+            }
+
+            TypedArray array = resources.obtainAttributes(attributeSet,
+                    com.android.internal.R.styleable.GameService);
+            gameSessionService = array.getString(
+                    com.android.internal.R.styleable.GameService_gameSessionService);
+            array.recycle();
+        } catch (PackageManager.NameNotFoundException | XmlPullParserException | IOException ex) {
+            Slog.w("Error while parsing meta-data for " + gameServiceServiceInfo.getComponentName(),
+                    ex);
+            return null;
+        }
+
+        if (TextUtils.isEmpty(gameSessionService)) {
+            Slog.w(TAG, "No gameSessionService specified");
+            return null;
+        }
+        ComponentName componentName =
+                new ComponentName(gameServiceServiceInfo.packageName, gameSessionService);
+
+        try {
+            mPackageManager.getServiceInfo(componentName, /* flags= */ 0);
+        } catch (PackageManager.NameNotFoundException ex) {
+            Slog.w(TAG, "GameSessionService does not exist: " + componentName);
+            return null;
+        }
+
+        return componentName;
+    }
+}
diff --git a/services/core/java/com/android/server/app/GameSessionRecord.java b/services/core/java/com/android/server/app/GameSessionRecord.java
new file mode 100644
index 0000000..329e9e8
--- /dev/null
+++ b/services/core/java/com/android/server/app/GameSessionRecord.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.app;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.service.games.IGameSession;
+
+import java.util.Objects;
+
+final class GameSessionRecord {
+
+    private final int mTaskId;
+    private final ComponentName mRootComponentName;
+    @Nullable
+    private final IGameSession mIGameSession;
+
+    static GameSessionRecord pendingGameSession(int taskId, ComponentName rootComponentName) {
+        return new GameSessionRecord(taskId, rootComponentName, /* gameSession= */ null);
+    }
+
+    private GameSessionRecord(
+            int taskId,
+            @NonNull ComponentName rootComponentName,
+            @Nullable IGameSession gameSession) {
+        this.mTaskId = taskId;
+        this.mRootComponentName = rootComponentName;
+        this.mIGameSession = gameSession;
+    }
+
+    @NonNull
+    public GameSessionRecord withGameSession(@NonNull IGameSession gameSession) {
+        Objects.requireNonNull(gameSession);
+        return new GameSessionRecord(mTaskId, mRootComponentName, gameSession);
+    }
+
+    @Nullable
+    public IGameSession getGameSession() {
+        return mIGameSession;
+    }
+
+    @Override
+    public String toString() {
+        return "GameSessionRecord{"
+                + "mTaskId="
+                + mTaskId
+                + ", mRootComponentName="
+                + mRootComponentName
+                + ", mIGameSession="
+                + mIGameSession
+                + '}';
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+
+        if (!(o instanceof GameSessionRecord)) {
+            return false;
+        }
+
+        GameSessionRecord that = (GameSessionRecord) o;
+        return mTaskId == that.mTaskId && mRootComponentName.equals(that.mRootComponentName)
+                && Objects.equals(mIGameSession, that.mIGameSession);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mTaskId, mRootComponentName, mIGameSession);
+    }
+}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 8615393..0879bec 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -3239,6 +3239,13 @@
         }
     }
 
+    private void enforceQueryStatePermission() {
+        if (mContext.checkCallingOrSelfPermission(Manifest.permission.QUERY_AUDIO_STATE)
+                != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("Missing QUERY_AUDIO_STATE permissions");
+        }
+    }
+
     private void enforceQueryStateOrModifyRoutingPermission() {
         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
                 != PackageManager.PERMISSION_GRANTED
@@ -4143,6 +4150,7 @@
 
     /** Get last audible volume before stream was muted. */
     public int getLastAudibleStreamVolume(int streamType) {
+        enforceQueryStatePermission();
         ensureValidStreamType(streamType);
         int device = getDeviceForStream(streamType);
         return (mStreamStates[streamType].getIndex(device) + 5) / 10;
@@ -9771,7 +9779,7 @@
                                      projection)) {
             Slog.w(TAG, "Permission denied to register audio policy for pid "
                     + Binder.getCallingPid() + " / uid " + Binder.getCallingUid()
-                    + ", need MODIFY_AUDIO_ROUTING or MediaProjection that can project audio");
+                    + ", need system permission or a MediaProjection that can project audio");
             return null;
         }
 
diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
index b333ed2..406b2dd2 100644
--- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
@@ -817,7 +817,7 @@
             // the same time if we still have a public client.
             while (clientIterator.hasNext()) {
                 PlayMonitorClient pmc = clientIterator.next();
-                if (pcdb.equals(pmc.mDispatcherCb)) {
+                if (pcdb.asBinder().equals(pmc.mDispatcherCb.asBinder())) {
                     pmc.release();
                     clientIterator.remove();
                 } else {
diff --git a/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java b/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java
index 2465ec5..6f71768 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java
@@ -38,8 +38,8 @@
 
     private static final String TAG = "Biometrics/AcquisitionClient";
 
-    private static final VibrationAttributes TOUCH_VIBRATION_ATTRIBUTES =
-            VibrationAttributes.createForUsage(VibrationAttributes.USAGE_TOUCH);
+    private static final VibrationAttributes HARDWARE_FEEDBACK_VIBRATION_ATTRIBUTES =
+            VibrationAttributes.createForUsage(VibrationAttributes.USAGE_HARDWARE_FEEDBACK);
 
     private static final VibrationEffect SUCCESS_VIBRATION_EFFECT =
             VibrationEffect.get(VibrationEffect.EFFECT_CLICK);
@@ -196,7 +196,7 @@
                     getContext().getOpPackageName(),
                     SUCCESS_VIBRATION_EFFECT,
                     getClass().getSimpleName() + "::success",
-                    TOUCH_VIBRATION_ATTRIBUTES);
+                    HARDWARE_FEEDBACK_VIBRATION_ATTRIBUTES);
         }
     }
 
@@ -207,7 +207,7 @@
                     getContext().getOpPackageName(),
                     ERROR_VIBRATION_EFFECT,
                     getClass().getSimpleName() + "::error",
-                    TOUCH_VIBRATION_ATTRIBUTES);
+                    HARDWARE_FEEDBACK_VIBRATION_ATTRIBUTES);
         }
     }
 }
diff --git a/services/core/java/com/android/server/communal/CommunalManagerService.java b/services/core/java/com/android/server/communal/CommunalManagerService.java
index df95bf5..2a6456d 100644
--- a/services/core/java/com/android/server/communal/CommunalManagerService.java
+++ b/services/core/java/com/android/server/communal/CommunalManagerService.java
@@ -16,117 +16,34 @@
 
 package com.android.server.communal;
 
-import static android.app.ActivityManager.INTENT_SENDER_ACTIVITY;
-import static android.app.communal.CommunalManager.ALLOW_COMMUNAL_MODE_BY_DEFAULT;
-import static android.app.communal.CommunalManager.ALLOW_COMMUNAL_MODE_WITH_USER_CONSENT;
-import static android.content.Intent.ACTION_PACKAGE_REMOVED;
-
-import static com.android.server.wm.ActivityInterceptorCallback.COMMUNAL_MODE_ORDERED_ID;
-
 import android.Manifest;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
-import android.app.KeyguardManager;
-import android.app.PendingIntent;
 import android.app.communal.ICommunalManager;
 import android.app.communal.ICommunalModeListener;
-import android.app.compat.CompatChanges;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
 import android.content.Context;
-import android.content.IIntentSender;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.IntentSender;
-import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.net.Uri;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.service.dreams.DreamManagerInternal;
-import android.text.TextUtils;
-import android.util.Log;
-import android.util.Slog;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.app.LaunchAfterAuthenticationActivity;
-import com.android.server.LocalServices;
 import com.android.server.SystemService;
-import com.android.server.wm.ActivityInterceptorCallback;
-import com.android.server.wm.ActivityTaskManagerInternal;
 
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
  * System service for handling Communal Mode state.
  */
 public final class CommunalManagerService extends SystemService {
-    private static final String TAG = CommunalManagerService.class.getSimpleName();
-    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
-    private static final String DELIMITER = ",";
     private final Context mContext;
-    private final ActivityTaskManagerInternal mAtmInternal;
-    private final KeyguardManager mKeyguardManager;
     private final AtomicBoolean mCommunalViewIsShowing = new AtomicBoolean(false);
     private final BinderService mBinderService;
-    private final PackageReceiver mPackageReceiver;
-    private final PackageManager mPackageManager;
-    private final DreamManagerInternal mDreamManagerInternal;
     private final RemoteCallbackList<ICommunalModeListener> mListeners =
             new RemoteCallbackList<>();
 
-    private final ActivityInterceptorCallback mActivityInterceptorCallback =
-            new ActivityInterceptorCallback() {
-                @Nullable
-                @Override
-                public ActivityInterceptResult intercept(ActivityInterceptorInfo info) {
-                    if (!shouldIntercept(info.aInfo)) {
-                        if (DEBUG) {
-                            Slog.d(TAG, "Activity allowed, not intercepting: "
-                                    + info.aInfo.getComponentName());
-                        }
-                        return null;
-                    }
-
-                    final IIntentSender target = mAtmInternal.getIntentSender(
-                            INTENT_SENDER_ACTIVITY,
-                            info.callingPackage,
-                            info.callingFeatureId,
-                            info.callingUid,
-                            info.userId,
-                            /* token= */null,
-                            /* resultWho= */ null,
-                            /* requestCode= */ 0,
-                            new Intent[]{info.intent},
-                            new String[]{info.resolvedType},
-                            PendingIntent.FLAG_IMMUTABLE,
-                            /* bOptions= */ null);
-
-                    return new ActivityInterceptResult(
-                            LaunchAfterAuthenticationActivity.createLaunchAfterAuthenticationIntent(
-                                    new IntentSender(target)),
-                            info.checkedOptions);
-
-                }
-            };
 
     public CommunalManagerService(Context context) {
         super(context);
         mContext = context;
-        mPackageManager = mContext.getPackageManager();
-        mAtmInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
-        mDreamManagerInternal = LocalServices.getService(DreamManagerInternal.class);
-        mKeyguardManager = mContext.getSystemService(KeyguardManager.class);
         mBinderService = new BinderService();
-        mPackageReceiver = new PackageReceiver(mContext);
     }
 
     @VisibleForTesting
@@ -139,116 +56,6 @@
         publishBinderService(Context.COMMUNAL_SERVICE, mBinderService);
     }
 
-    @Override
-    public void onBootPhase(int phase) {
-        if (phase != SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) return;
-        mAtmInternal.registerActivityStartInterceptor(
-                COMMUNAL_MODE_ORDERED_ID,
-                mActivityInterceptorCallback);
-        mPackageReceiver.register();
-        removeUninstalledPackagesFromSettings();
-    }
-
-    @Override
-    public void finalize() {
-        mPackageReceiver.unregister();
-    }
-
-    private Set<String> getUserEnabledApps() {
-        final String encodedApps = Settings.Secure.getStringForUser(
-                mContext.getContentResolver(),
-                Settings.Secure.COMMUNAL_MODE_PACKAGES,
-                UserHandle.USER_SYSTEM);
-
-        return TextUtils.isEmpty(encodedApps)
-                ? Collections.emptySet()
-                : new HashSet<>(Arrays.asList(encodedApps.split(DELIMITER)));
-    }
-
-    private void removeUninstalledPackagesFromSettings() {
-        for (String packageName : getUserEnabledApps()) {
-            if (!isPackageInstalled(packageName, mPackageManager)) {
-                removePackageFromSettings(packageName);
-            }
-        }
-    }
-
-    private void removePackageFromSettings(String packageName) {
-        Set<String> enabledPackages = getUserEnabledApps();
-        if (enabledPackages.remove(packageName)) {
-            Settings.Secure.putStringForUser(
-                    mContext.getContentResolver(),
-                    Settings.Secure.COMMUNAL_MODE_PACKAGES,
-                    String.join(DELIMITER, enabledPackages),
-                    UserHandle.USER_SYSTEM);
-        }
-    }
-
-    @VisibleForTesting
-    static boolean isPackageInstalled(String packageName, PackageManager packageManager) {
-        if (packageManager == null) return false;
-        try {
-            return packageManager.getPackageInfo(packageName, 0) != null;
-        } catch (PackageManager.NameNotFoundException e) {
-            return false;
-        }
-    }
-
-    private boolean isAppAllowed(ApplicationInfo appInfo) {
-        if (isActiveDream(appInfo) || isChangeEnabled(ALLOW_COMMUNAL_MODE_BY_DEFAULT, appInfo)) {
-            return true;
-        }
-
-        if (!isChangeEnabled(ALLOW_COMMUNAL_MODE_WITH_USER_CONSENT, appInfo)) {
-            if (DEBUG) Slog.d(TAG, "App is not allowlisted: " + appInfo.packageName);
-            return false;
-        }
-
-        if (!getUserEnabledApps().contains(appInfo.packageName)) {
-            if (DEBUG) Slog.d(TAG, "App does not have user consent: " + appInfo.packageName);
-            return false;
-        }
-
-        return true;
-    }
-
-    private boolean isActiveDream(ApplicationInfo appInfo) {
-        final ComponentName activeDream = mDreamManagerInternal.getActiveDreamComponent(
-                /* doze= */ false);
-        final ComponentName activeDoze = mDreamManagerInternal.getActiveDreamComponent(
-                /* doze= */ true);
-        return isFromPackage(activeDream, appInfo) || isFromPackage(activeDoze, appInfo);
-    }
-
-    private static boolean isFromPackage(ComponentName componentName, ApplicationInfo appInfo) {
-        if (componentName == null) return false;
-        return TextUtils.equals(appInfo.packageName, componentName.getPackageName());
-    }
-
-    private static boolean isChangeEnabled(long changeId, ApplicationInfo appInfo) {
-        return CompatChanges.isChangeEnabled(changeId, appInfo.packageName, UserHandle.SYSTEM);
-    }
-
-    private boolean shouldIntercept(ActivityInfo activityInfo) {
-        if (!mCommunalViewIsShowing.get() || !mKeyguardManager.isKeyguardLocked()) return false;
-        ApplicationInfo appInfo = activityInfo.applicationInfo;
-        // Dreams are allowed to show, and don't require the showWhenLocked attribute.
-        if (isActiveDream(appInfo)) return false;
-
-        // If the activity doesn't have showWhenLocked enabled, disallow the activity.
-        final boolean showWhenLocked =
-                (activityInfo.flags & ActivityInfo.FLAG_SHOW_WHEN_LOCKED) != 0;
-        if (!showWhenLocked) {
-            if (DEBUG) {
-                Slog.d(TAG, "Activity does not contain showWhenLocked attribute: "
-                        + activityInfo.getComponentName());
-            }
-            return true;
-        }
-
-        return !isAppAllowed(appInfo);
-    }
-
     private void dispatchCommunalMode(boolean isShowing) {
         synchronized (mListeners) {
             int i = mListeners.beginBroadcast();
@@ -319,49 +126,4 @@
             }
         }
     }
-
-    /**
-     * A {@link BroadcastReceiver} that listens on package removed events and updates any stored
-     * package state in Settings.
-     */
-    private final class PackageReceiver extends BroadcastReceiver {
-        private final Context mContext;
-        private final IntentFilter mIntentFilter;
-
-        private PackageReceiver(Context context) {
-            mContext = context;
-            mIntentFilter = new IntentFilter();
-            mIntentFilter.addAction(ACTION_PACKAGE_REMOVED);
-            mIntentFilter.addDataScheme("package");
-        }
-
-        private void register() {
-            mContext.registerReceiverAsUser(
-                    this,
-                    UserHandle.SYSTEM,
-                    mIntentFilter,
-                    /* broadcastPermission= */null,
-                    /* scheduler= */ null);
-        }
-
-        private void unregister() {
-            mContext.unregisterReceiver(this);
-        }
-
-        @Override
-        public void onReceive(@NonNull final Context context, @NonNull final Intent intent) {
-            final Uri data = intent.getData();
-            if (data == null) {
-                Slog.w(TAG, "Failed to get package name in package receiver");
-                return;
-            }
-            final String packageName = data.getSchemeSpecificPart();
-            final String action = intent.getAction();
-            if (ACTION_PACKAGE_REMOVED.equals(action)) {
-                removePackageFromSettings(packageName);
-            } else {
-                Slog.w(TAG, "Unsupported action in package receiver: " + action);
-            }
-        }
-    }
 }
diff --git a/services/core/java/com/android/server/compat/CompatConfig.java b/services/core/java/com/android/server/compat/CompatConfig.java
index e2e56ae..9dd7daf 100644
--- a/services/core/java/com/android/server/compat/CompatConfig.java
+++ b/services/core/java/com/android/server/compat/CompatConfig.java
@@ -36,6 +36,8 @@
 import com.android.internal.compat.CompatibilityChangeConfig;
 import com.android.internal.compat.CompatibilityChangeInfo;
 import com.android.internal.compat.CompatibilityOverrideConfig;
+import com.android.internal.compat.CompatibilityOverridesByPackageConfig;
+import com.android.internal.compat.CompatibilityOverridesToRemoveByPackageConfig;
 import com.android.internal.compat.CompatibilityOverridesToRemoveConfig;
 import com.android.internal.compat.IOverrideValidator;
 import com.android.internal.compat.OverrideAllowedState;
@@ -220,15 +222,47 @@
     }
 
     /**
-     * Overrides the enabled state for a given change and app.
+     * Adds compat config overrides for multiple packages.
      *
+     * <p>Equivalent to calling
+     * {@link #addPackageOverrides(CompatibilityOverrideConfig, String, boolean)} on each entry
+     * in {@code overridesByPackage}, but the state of the compat config will be updated only
+     * once instead of for each package.
      *
-     * @param overrides            list of overrides to default changes config.
-     * @param packageName          app for which the overrides will be applied.
+     * @param overridesByPackage map from package name to compat config overrides to add for that
+     *                           package.
+     * @param skipUnknownChangeIds whether to skip unknown change IDs in {@code overridesByPackage}.
+     */
+    synchronized void addAllPackageOverrides(
+            CompatibilityOverridesByPackageConfig overridesByPackage,
+            boolean skipUnknownChangeIds) {
+        for (String packageName : overridesByPackage.packageNameToOverrides.keySet()) {
+            addPackageOverridesWithoutSaving(
+                    overridesByPackage.packageNameToOverrides.get(packageName), packageName,
+                    skipUnknownChangeIds);
+        }
+        saveOverrides();
+        invalidateCache();
+    }
+
+    /**
+     * Adds compat config overrides for a given package.
+     *
+     * <p>Note, package overrides are not persistent and will be lost on system or runtime restart.
+     *
+     * @param overrides   list of compat config overrides to add for the given package.
+     * @param packageName app for which the overrides will be applied.
      * @param skipUnknownChangeIds whether to skip unknown change IDs in {@code overrides}.
      */
     synchronized void addPackageOverrides(CompatibilityOverrideConfig overrides,
             String packageName, boolean skipUnknownChangeIds) {
+        addPackageOverridesWithoutSaving(overrides, packageName, skipUnknownChangeIds);
+        saveOverrides();
+        invalidateCache();
+    }
+
+    private void addPackageOverridesWithoutSaving(CompatibilityOverrideConfig overrides,
+            String packageName, boolean skipUnknownChangeIds) {
         for (Long changeId : overrides.overrides.keySet()) {
             if (skipUnknownChangeIds && !isKnownChangeId(changeId)) {
                 Slog.w(TAG, "Trying to add overrides for unknown Change ID " + changeId + ". "
@@ -237,8 +271,6 @@
             }
             addOverrideUnsafe(changeId, packageName, overrides.overrides.get(changeId));
         }
-        saveOverrides();
-        invalidateCache();
     }
 
     private boolean addOverrideUnsafe(long changeId, String packageName,
@@ -344,6 +376,36 @@
     }
 
     /**
+     * Removes overrides with a specified change ID that were previously added via
+     * {@link #addOverride(long, String, boolean)} or
+     * {@link #addPackageOverrides(CompatibilityOverrideConfig, String, boolean)} for multiple
+     * packages.
+     *
+     * <p>Equivalent to calling
+     * {@link #removePackageOverrides(CompatibilityOverridesToRemoveConfig, String)} on each entry
+     * in {@code overridesToRemoveByPackage}, but the state of the compat config will be updated
+     * only once instead of for each package.
+     *
+     * @param overridesToRemoveByPackage map from package name to a list of change IDs for
+     *                                   which to restore the default behaviour for that
+     *                                   package.
+     */
+    synchronized void removeAllPackageOverrides(
+            CompatibilityOverridesToRemoveByPackageConfig overridesToRemoveByPackage) {
+        boolean shouldInvalidateCache = false;
+        for (String packageName :
+                overridesToRemoveByPackage.packageNameToOverridesToRemove.keySet()) {
+            shouldInvalidateCache |= removePackageOverridesWithoutSaving(
+                    overridesToRemoveByPackage.packageNameToOverridesToRemove.get(packageName),
+                    packageName);
+        }
+        if (shouldInvalidateCache) {
+            saveOverrides();
+            invalidateCache();
+        }
+    }
+
+    /**
      * Removes all overrides previously added via {@link #addOverride(long, String, boolean)} or
      * {@link #addPackageOverrides(CompatibilityOverrideConfig, String, boolean)} for a certain
      * package.
@@ -377,6 +439,16 @@
      */
     synchronized void removePackageOverrides(CompatibilityOverridesToRemoveConfig overridesToRemove,
             String packageName) {
+        boolean shouldInvalidateCache = removePackageOverridesWithoutSaving(overridesToRemove,
+                packageName);
+        if (shouldInvalidateCache) {
+            saveOverrides();
+            invalidateCache();
+        }
+    }
+
+    private boolean removePackageOverridesWithoutSaving(
+            CompatibilityOverridesToRemoveConfig overridesToRemove, String packageName) {
         boolean shouldInvalidateCache = false;
         for (Long changeId : overridesToRemove.changeIds) {
             if (!isKnownChangeId(changeId)) {
@@ -386,10 +458,7 @@
             }
             shouldInvalidateCache |= removeOverrideUnsafe(changeId, packageName);
         }
-        if (shouldInvalidateCache) {
-            saveOverrides();
-            invalidateCache();
-        }
+        return shouldInvalidateCache;
     }
 
     private long[] getAllowedChangesSinceTargetSdkForPackage(String packageName,
diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java
index 6ea89d4..aab6281 100644
--- a/services/core/java/com/android/server/compat/PlatformCompat.java
+++ b/services/core/java/com/android/server/compat/PlatformCompat.java
@@ -47,6 +47,8 @@
 import com.android.internal.compat.CompatibilityChangeConfig;
 import com.android.internal.compat.CompatibilityChangeInfo;
 import com.android.internal.compat.CompatibilityOverrideConfig;
+import com.android.internal.compat.CompatibilityOverridesByPackageConfig;
+import com.android.internal.compat.CompatibilityOverridesToRemoveByPackageConfig;
 import com.android.internal.compat.CompatibilityOverridesToRemoveConfig;
 import com.android.internal.compat.IOverrideValidator;
 import com.android.internal.compat.IPlatformCompat;
@@ -226,9 +228,19 @@
     }
 
     @Override
+    public void putAllOverridesOnReleaseBuilds(
+            CompatibilityOverridesByPackageConfig overridesByPackage) {
+        checkCompatChangeOverrideOverridablePermission();
+        for (CompatibilityOverrideConfig overrides :
+                overridesByPackage.packageNameToOverrides.values()) {
+            checkAllCompatOverridesAreOverridable(overrides.overrides.keySet());
+        }
+        mCompatConfig.addAllPackageOverrides(overridesByPackage, /* skipUnknownChangeIds= */ true);
+    }
+
+    @Override
     public void putOverridesOnReleaseBuilds(CompatibilityOverrideConfig overrides,
             String packageName) {
-        // TODO(b/183630314): Unify the permission enforcement with the other setOverrides* methods.
         checkCompatChangeOverrideOverridablePermission();
         checkAllCompatOverridesAreOverridable(overrides.overrides.keySet());
         mCompatConfig.addPackageOverrides(overrides, packageName, /* skipUnknownChangeIds= */ true);
@@ -280,10 +292,20 @@
     }
 
     @Override
+    public void removeAllOverridesOnReleaseBuilds(
+            CompatibilityOverridesToRemoveByPackageConfig overridesToRemoveByPackage) {
+        checkCompatChangeOverrideOverridablePermission();
+        for (CompatibilityOverridesToRemoveConfig overridesToRemove :
+                overridesToRemoveByPackage.packageNameToOverridesToRemove.values()) {
+            checkAllCompatOverridesAreOverridable(overridesToRemove.changeIds);
+        }
+        mCompatConfig.removeAllPackageOverrides(overridesToRemoveByPackage);
+    }
+
+    @Override
     public void removeOverridesOnReleaseBuilds(
             CompatibilityOverridesToRemoveConfig overridesToRemove,
             String packageName) {
-        // TODO(b/183630314): Unify the permission enforcement with the other setOverrides* methods.
         checkCompatChangeOverrideOverridablePermission();
         checkAllCompatOverridesAreOverridable(overridesToRemove.changeIds);
         mCompatConfig.removePackageOverrides(overridesToRemove, packageName);
diff --git a/services/core/java/com/android/server/compat/overrides/AppCompatOverridesService.java b/services/core/java/com/android/server/compat/overrides/AppCompatOverridesService.java
index 7e58b6c..880dbf6 100644
--- a/services/core/java/com/android/server/compat/overrides/AppCompatOverridesService.java
+++ b/services/core/java/com/android/server/compat/overrides/AppCompatOverridesService.java
@@ -41,11 +41,14 @@
 import android.os.ServiceManager;
 import android.provider.DeviceConfig;
 import android.provider.DeviceConfig.Properties;
+import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Slog;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.compat.CompatibilityOverrideConfig;
+import com.android.internal.compat.CompatibilityOverridesByPackageConfig;
+import com.android.internal.compat.CompatibilityOverridesToRemoveByPackageConfig;
 import com.android.internal.compat.CompatibilityOverridesToRemoveConfig;
 import com.android.internal.compat.IPlatformCompat;
 import com.android.server.SystemService;
@@ -150,6 +153,9 @@
         Set<String> packageNames = new ArraySet<>(properties.getKeyset());
         packageNames.remove(FLAG_OWNED_CHANGE_IDS);
         packageNames.remove(FLAG_REMOVE_OVERRIDES);
+        Map<String, CompatibilityOverrideConfig> packageNameToOverridesToAdd = new ArrayMap<>();
+        Map<String, CompatibilityOverridesToRemoveConfig> packageNameToOverridesToRemove =
+                new ArrayMap<>();
         for (String packageName : packageNames) {
             Long versionCode = getVersionCodeOrNull(packageName);
             if (versionCode == null) {
@@ -157,11 +163,30 @@
                 continue;
             }
 
-            applyPackageOverrides(properties.getString(packageName, /* defaultValue= */ ""),
-                    packageName, versionCode, ownedChangeIds,
-                    packageToChangeIdsToSkip.getOrDefault(packageName, emptySet()),
-                    /* removeOtherOwnedOverrides= */ true);
+            Set<Long> changeIdsToSkip = packageToChangeIdsToSkip.getOrDefault(packageName,
+                    emptySet());
+            Map<Long, PackageOverride> overridesToAdd = mOverridesParser.parsePackageOverrides(
+                    properties.getString(packageName, /* defaultValue= */ ""), packageName,
+                    versionCode, changeIdsToSkip);
+            if (!overridesToAdd.isEmpty()) {
+                packageNameToOverridesToAdd.put(packageName,
+                        new CompatibilityOverrideConfig(overridesToAdd));
+            }
+
+            Set<Long> overridesToRemove = new ArraySet<>();
+            for (Long changeId : ownedChangeIds) {
+                if (!overridesToAdd.containsKey(changeId) && !changeIdsToSkip.contains(changeId)) {
+                    overridesToRemove.add(changeId);
+                }
+            }
+            if (!overridesToRemove.isEmpty()) {
+                packageNameToOverridesToRemove.put(packageName,
+                        new CompatibilityOverridesToRemoveConfig(overridesToRemove));
+            }
         }
+
+        putAllPackageOverrides(packageNameToOverridesToAdd);
+        removeAllPackageOverrides(packageNameToOverridesToRemove);
     }
 
     /**
@@ -177,42 +202,15 @@
             // We apply overrides for each namespace separately so that if there is a failure for
             // one namespace, the other namespaces won't be affected.
             Set<Long> ownedChangeIds = getOwnedChangeIds(namespace);
-            applyPackageOverrides(
-                    DeviceConfig.getString(namespace, packageName, /* defaultValue= */ ""),
-                    packageName, versionCode, ownedChangeIds,
+            putPackageOverrides(packageName, mOverridesParser.parsePackageOverrides(
+                    DeviceConfig.getString(namespace, packageName, /* defaultValue= */""),
+                    packageName, versionCode,
                     getOverridesToRemove(namespace, ownedChangeIds).getOrDefault(packageName,
-                            emptySet()), /* removeOtherOwnedOverrides */ false);
+                            emptySet())));
         }
     }
 
     /**
-     * Calls {@link AppCompatOverridesParser#parsePackageOverrides} on the given arguments and adds
-     * the resulting overrides via {@link IPlatformCompat#putOverridesOnReleaseBuilds}.
-     *
-     * <p>In addition, if {@code removeOtherOwnedOverrides} is true, removes any override that
-     * wasn't just added, whose change ID is in {@code ownedChangeIds} but not in {@code
-     * changeIdsToSkip}, via {@link IPlatformCompat#removeOverridesOnReleaseBuilds}.
-     */
-    private void applyPackageOverrides(String configStr, String packageName, long versionCode,
-            Set<Long> ownedChangeIds, Set<Long> changeIdsToSkip,
-            boolean removeOtherOwnedOverrides) {
-        Map<Long, PackageOverride> overridesToAdd = mOverridesParser.parsePackageOverrides(
-                configStr, packageName, versionCode, changeIdsToSkip);
-        putPackageOverrides(packageName, overridesToAdd);
-
-        if (!removeOtherOwnedOverrides) {
-            return;
-        }
-        Set<Long> overridesToRemove = new ArraySet<>();
-        for (Long changeId : ownedChangeIds) {
-            if (!overridesToAdd.containsKey(changeId) && !changeIdsToSkip.contains(changeId)) {
-                overridesToRemove.add(changeId);
-            }
-        }
-        removePackageOverrides(packageName, overridesToRemove);
-    }
-
-    /**
      * Removes all owned overrides in all supported namespaces for the given {@code packageName}.
      *
      * <p>If a certain namespace doesn't have a package override flag for the given {@code
@@ -231,14 +229,18 @@
     }
 
     /**
-     * Calls {@link IPlatformCompat#removeOverridesOnReleaseBuilds} on each package name and
-     * respective change IDs in {@code overridesToRemove}.
+     * Calls {@link IPlatformCompat#removeAllOverridesOnReleaseBuilds} on {@code
+     * packageNameToOverridesToRemove}.
      */
-    private void removeOverrides(Map<String, Set<Long>> overridesToRemove) {
-        for (Map.Entry<String, Set<Long>> packageNameAndOverrides : overridesToRemove.entrySet()) {
-            removePackageOverrides(packageNameAndOverrides.getKey(),
-                    packageNameAndOverrides.getValue());
+    private void removeOverrides(Map<String, Set<Long>> packageNameToOverridesToRemove) {
+        Map<String, CompatibilityOverridesToRemoveConfig> packageNameToConfig =
+                new ArrayMap<>();
+        for (Map.Entry<String, Set<Long>> packageNameAndChangeIds :
+                packageNameToOverridesToRemove.entrySet()) {
+            packageNameToConfig.put(packageNameAndChangeIds.getKey(),
+                    new CompatibilityOverridesToRemoveConfig(packageNameAndChangeIds.getValue()));
         }
+        removeAllPackageOverrides(packageNameToConfig);
     }
 
     /**
@@ -262,6 +264,20 @@
                 DeviceConfig.getString(namespace, FLAG_OWNED_CHANGE_IDS, /* defaultValue= */ ""));
     }
 
+    private void putAllPackageOverrides(
+            Map<String, CompatibilityOverrideConfig> packageNameToOverrides) {
+        if (packageNameToOverrides.isEmpty()) {
+            return;
+        }
+        CompatibilityOverridesByPackageConfig config = new CompatibilityOverridesByPackageConfig(
+                packageNameToOverrides);
+        try {
+            mPlatformCompat.putAllOverridesOnReleaseBuilds(config);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Failed to call IPlatformCompat#putAllOverridesOnReleaseBuilds", e);
+        }
+    }
+
     private void putPackageOverrides(String packageName,
             Map<Long, PackageOverride> overridesToAdd) {
         if (overridesToAdd.isEmpty()) {
@@ -271,7 +287,21 @@
         try {
             mPlatformCompat.putOverridesOnReleaseBuilds(config, packageName);
         } catch (RemoteException e) {
-            Slog.w(TAG, "Failed to call IPlatformCompat#putOverridesOnReleaseBuilds", e);
+            Slog.e(TAG, "Failed to call IPlatformCompat#putOverridesOnReleaseBuilds", e);
+        }
+    }
+
+    private void removeAllPackageOverrides(
+            Map<String, CompatibilityOverridesToRemoveConfig> packageNameToOverridesToRemove) {
+        if (packageNameToOverridesToRemove.isEmpty()) {
+            return;
+        }
+        CompatibilityOverridesToRemoveByPackageConfig config =
+                new CompatibilityOverridesToRemoveByPackageConfig(packageNameToOverridesToRemove);
+        try {
+            mPlatformCompat.removeAllOverridesOnReleaseBuilds(config);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Failed to call IPlatformCompat#removeAllOverridesOnReleaseBuilds", e);
         }
     }
 
@@ -284,7 +314,7 @@
         try {
             mPlatformCompat.removeOverridesOnReleaseBuilds(config, packageName);
         } catch (RemoteException e) {
-            Slog.w(TAG, "Failed to call IPlatformCompat#removeOverridesOnReleaseBuilds", e);
+            Slog.e(TAG, "Failed to call IPlatformCompat#removeOverridesOnReleaseBuilds", e);
         }
     }
 
diff --git a/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
index a56a8ea..72e900b 100644
--- a/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
+++ b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
@@ -25,9 +25,7 @@
 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
 import static android.net.NetworkPolicy.LIMIT_DISABLED;
 import static android.net.NetworkPolicy.WARNING_DISABLED;
-import static android.net.NetworkTemplate.NETWORK_TYPE_ALL;
 import static android.net.NetworkTemplate.OEM_MANAGED_ALL;
-import static android.net.NetworkTemplate.SUBSCRIBER_ID_MATCH_RULE_EXACT;
 import static android.provider.Settings.Global.NETWORK_DEFAULT_DAILY_MULTIPATH_QUOTA_BYTES;
 import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
 
@@ -77,6 +75,8 @@
 import java.time.ZoneOffset;
 import java.time.ZonedDateTime;
 import java.time.temporal.ChronoUnit;
+import java.util.Objects;
+import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.TimeUnit;
 
@@ -224,12 +224,13 @@
                         "Can't get TelephonyManager for subId %d", subId));
             }
 
-            subscriberId = tele.getSubscriberId();
-            mNetworkTemplate = new NetworkTemplate(
-                    NetworkTemplate.MATCH_MOBILE, subscriberId, new String[] { subscriberId },
-                    null, NetworkStats.METERED_YES, NetworkStats.ROAMING_ALL,
-                    NetworkStats.DEFAULT_NETWORK_NO, NETWORK_TYPE_ALL, OEM_MANAGED_ALL,
-                    SUBSCRIBER_ID_MATCH_RULE_EXACT);
+            subscriberId = Objects.requireNonNull(tele.getSubscriberId(),
+                    "Null subscriber Id for subId " + subId);
+            mNetworkTemplate = new NetworkTemplate.Builder(NetworkTemplate.MATCH_MOBILE)
+                    .setSubscriberIds(Set.of(subscriberId))
+                    .setMeteredness(NetworkStats.METERED_YES)
+                    .setDefaultNetworkStatus(NetworkStats.DEFAULT_NETWORK_NO)
+                    .build();
             mUsageCallback = new UsageCallback() {
                 @Override
                 public void onThresholdReached(int networkType, String subscriberId) {
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index bf4ef48..6a716cb 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -17,6 +17,8 @@
 package com.android.server.connectivity;
 
 import static android.Manifest.permission.BIND_VPN_SERVICE;
+import static android.Manifest.permission.CONTROL_VPN;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
 import static android.net.RouteInfo.RTN_THROW;
 import static android.net.RouteInfo.RTN_UNREACHABLE;
@@ -932,6 +934,7 @@
      * - oldPackage null, newPackage non-null: ConfirmDialog calling prepareVpn().
      * - oldPackage null, newPackage=LEGACY_VPN: Used internally to disconnect
      *   and revoke any current app VPN and re-prepare legacy vpn.
+     * - oldPackage null, newPackage null: always returns true for backward compatibility.
      *
      * TODO: Rename the variables - or split this method into two - and end this confusion.
      * TODO: b/29032008 Migrate code from prepare(oldPackage=non-null, newPackage=LEGACY_VPN)
@@ -945,6 +948,18 @@
      */
     public synchronized boolean prepare(
             String oldPackage, String newPackage, @VpnManager.VpnType int vpnType) {
+        // Except for Settings and VpnDialogs, the caller should be matched one of oldPackage or
+        // newPackage. Otherwise, non VPN owner might get the VPN always-on status of the VPN owner.
+        // See b/191382886.
+        if (mContext.checkCallingOrSelfPermission(CONTROL_VPN) != PERMISSION_GRANTED) {
+            if (oldPackage != null) {
+                verifyCallingUidAndPackage(oldPackage);
+            }
+            if (newPackage != null) {
+                verifyCallingUidAndPackage(newPackage);
+            }
+        }
+
         if (oldPackage != null) {
             // Stop an existing always-on VPN from being dethroned by other apps.
             if (mAlwaysOn && !isCurrentPreparedPackage(oldPackage)) {
@@ -1446,7 +1461,10 @@
             // parameters. If that fails, disconnect.
             if (oldConfig != null
                     && updateLinkPropertiesInPlaceIfPossible(mNetworkAgent, oldConfig)) {
-                // Keep mNetworkAgent unchanged
+                // Update underlying networks if it is changed.
+                if (!Arrays.equals(oldConfig.underlyingNetworks, config.underlyingNetworks)) {
+                    setUnderlyingNetworks(config.underlyingNetworks);
+                }
             } else {
                 // Initialize the state for a new agent, while keeping the old one connected
                 // in case this new connection fails.
@@ -1859,14 +1877,13 @@
     }
 
     private void enforceControlPermission() {
-        mContext.enforceCallingPermission(Manifest.permission.CONTROL_VPN, "Unauthorized Caller");
+        mContext.enforceCallingPermission(CONTROL_VPN, "Unauthorized Caller");
     }
 
     private void enforceControlPermissionOrInternalCaller() {
         // Require the caller to be either an application with CONTROL_VPN permission or a process
         // in the system server.
-        mContext.enforceCallingOrSelfPermission(Manifest.permission.CONTROL_VPN,
-                "Unauthorized Caller");
+        mContext.enforceCallingOrSelfPermission(CONTROL_VPN, "Unauthorized Caller");
     }
 
     private void enforceSettingsPermission() {
@@ -3176,8 +3193,9 @@
     }
 
     private void verifyCallingUidAndPackage(String packageName) {
-        if (getAppUid(packageName, mUserId) != Binder.getCallingUid()) {
-            throw new SecurityException("Mismatched package and UID");
+        final int callingUid = Binder.getCallingUid();
+        if (getAppUid(packageName, mUserId) != callingUid) {
+            throw new SecurityException(packageName + " does not belong to uid " + callingUid);
         }
     }
 
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index c0a6abf..c4f2b14 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -714,7 +714,6 @@
                         display.getDisplayInfoLocked().shouldConstrainMetricsForLauncher;
                 if (display.setDisplayInfoOverrideFromWindowManagerLocked(info)) {
                     handleLogicalDisplayChangedLocked(display);
-                    scheduleTraversalLocked(false);
                 }
             }
         }
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 2dfaa8b..c4d02c7 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -50,6 +50,8 @@
 import android.provider.Settings;
 import android.util.Log;
 import android.util.MathUtils;
+import android.util.MutableFloat;
+import android.util.MutableInt;
 import android.util.Slog;
 import android.util.TimeUtils;
 import android.view.Display;
@@ -1354,6 +1356,7 @@
 
         // Animate the screen brightness when the screen is on or dozing.
         // Skip the animation when the screen is off or suspended or transition to/from VR.
+        boolean brightnessAdjusted = false;
         if (!mPendingScreenOff) {
             if (mSkipScreenOnBrightnessRamp) {
                 if (state == Display.STATE_ON) {
@@ -1446,15 +1449,19 @@
                     // slider event so notify as if the system changed the brightness.
                     userInitiatedChange = false;
                 }
-                notifyBrightnessChanged(brightnessState, userInitiatedChange,
+                notifyBrightnessTrackerChanged(brightnessState, userInitiatedChange,
                         hadUserBrightnessPoint);
             }
 
             // We save the brightness info *after* the brightness setting has been changed and
             // adjustments made so that the brightness info reflects the latest value.
-            saveBrightnessInfo(getScreenBrightnessSetting(), animateValue);
+            brightnessAdjusted = saveBrightnessInfo(getScreenBrightnessSetting(), animateValue);
         } else {
-            saveBrightnessInfo(getScreenBrightnessSetting());
+            brightnessAdjusted = saveBrightnessInfo(getScreenBrightnessSetting());
+        }
+
+        if (brightnessAdjusted) {
+            postBrightnessChangeRunnable();
         }
 
         // Log any changes to what is currently driving the brightness setting.
@@ -1570,31 +1577,50 @@
     public BrightnessInfo getBrightnessInfo() {
         synchronized (mCachedBrightnessInfo) {
             return new BrightnessInfo(
-                    mCachedBrightnessInfo.brightness,
-                    mCachedBrightnessInfo.adjustedBrightness,
-                    mCachedBrightnessInfo.brightnessMin,
-                    mCachedBrightnessInfo.brightnessMax,
-                    mCachedBrightnessInfo.hbmMode,
-                    mCachedBrightnessInfo.highBrightnessTransitionPoint);
+                    mCachedBrightnessInfo.brightness.value,
+                    mCachedBrightnessInfo.adjustedBrightness.value,
+                    mCachedBrightnessInfo.brightnessMin.value,
+                    mCachedBrightnessInfo.brightnessMax.value,
+                    mCachedBrightnessInfo.hbmMode.value,
+                    mCachedBrightnessInfo.hbmTransitionPoint.value);
         }
     }
 
-    private void saveBrightnessInfo(float brightness) {
-        saveBrightnessInfo(brightness, brightness);
+    private boolean saveBrightnessInfo(float brightness) {
+        return saveBrightnessInfo(brightness, brightness);
     }
 
-    private void saveBrightnessInfo(float brightness, float adjustedBrightness) {
+    private boolean saveBrightnessInfo(float brightness, float adjustedBrightness) {
         synchronized (mCachedBrightnessInfo) {
-            mCachedBrightnessInfo.brightness = brightness;
-            mCachedBrightnessInfo.adjustedBrightness = adjustedBrightness;
-            mCachedBrightnessInfo.brightnessMin = mHbmController.getCurrentBrightnessMin();
-            mCachedBrightnessInfo.brightnessMax = mHbmController.getCurrentBrightnessMax();
-            mCachedBrightnessInfo.hbmMode = mHbmController.getHighBrightnessMode();
-            mCachedBrightnessInfo.highBrightnessTransitionPoint =
-                mHbmController.getTransitionPoint();
+            boolean changed = false;
+
+            changed |=
+                mCachedBrightnessInfo.checkAndSetFloat(mCachedBrightnessInfo.brightness,
+                        brightness);
+            changed |=
+                mCachedBrightnessInfo.checkAndSetFloat(mCachedBrightnessInfo.adjustedBrightness,
+                        adjustedBrightness);
+            changed |=
+                mCachedBrightnessInfo.checkAndSetFloat(mCachedBrightnessInfo.brightnessMin,
+                        mHbmController.getCurrentBrightnessMin());
+            changed |=
+                mCachedBrightnessInfo.checkAndSetFloat(mCachedBrightnessInfo.brightnessMax,
+                        mHbmController.getCurrentBrightnessMax());
+            changed |=
+                mCachedBrightnessInfo.checkAndSetInt(mCachedBrightnessInfo.hbmMode,
+                        mHbmController.getHighBrightnessMode());
+            changed |=
+                mCachedBrightnessInfo.checkAndSetFloat(mCachedBrightnessInfo.hbmTransitionPoint,
+                        mHbmController.getTransitionPoint());
+
+            return changed;
         }
     }
 
+    void postBrightnessChangeRunnable() {
+        mHandler.post(mOnBrightnessChangeRunnable);
+    }
+
     private HighBrightnessModeController createHbmControllerLocked() {
         final DisplayDevice device = mLogicalDisplay.getPrimaryDisplayDeviceLocked();
         final DisplayDeviceConfig ddConfig = device.getDisplayDeviceConfig();
@@ -1607,7 +1633,7 @@
                 PowerManager.BRIGHTNESS_MIN, PowerManager.BRIGHTNESS_MAX, hbmData,
                 () -> {
                     sendUpdatePowerStateLocked();
-                    mHandler.post(mOnBrightnessChangeRunnable);
+                    postBrightnessChangeRunnable();
                     // TODO(b/192258832): Switch the HBMChangeCallback to a listener pattern.
                     if (mAutomaticBrightnessController != null) {
                         mAutomaticBrightnessController.update();
@@ -2109,7 +2135,7 @@
     private void setCurrentScreenBrightness(float brightnessValue) {
         if (brightnessValue != mCurrentScreenBrightnessSetting) {
             mCurrentScreenBrightnessSetting = brightnessValue;
-            mHandler.post(mOnBrightnessChangeRunnable);
+            postBrightnessChangeRunnable();
         }
     }
 
@@ -2161,7 +2187,7 @@
         return true;
     }
 
-    private void notifyBrightnessChanged(float brightness, boolean userInitiated,
+    private void notifyBrightnessTrackerChanged(float brightness, boolean userInitiated,
             boolean hadUserDataPoint) {
         final float brightnessInNits = convertToNits(brightness);
         if (mPowerRequest.useAutoBrightness && brightnessInNits >= 0.0f
@@ -2271,16 +2297,17 @@
         pw.println("  mColorFadeFadesConfig=" + mColorFadeFadesConfig);
         pw.println("  mColorFadeEnabled=" + mColorFadeEnabled);
         synchronized (mCachedBrightnessInfo) {
-            pw.println("  mCachedBrightnessInfo.brightness=" + mCachedBrightnessInfo.brightness);
+            pw.println("  mCachedBrightnessInfo.brightness=" +
+                    mCachedBrightnessInfo.brightness.value);
             pw.println("  mCachedBrightnessInfo.adjustedBrightness=" +
-                    mCachedBrightnessInfo.adjustedBrightness);
+                    mCachedBrightnessInfo.adjustedBrightness.value);
             pw.println("  mCachedBrightnessInfo.brightnessMin=" +
-                    mCachedBrightnessInfo.brightnessMin);
+                    mCachedBrightnessInfo.brightnessMin.value);
             pw.println("  mCachedBrightnessInfo.brightnessMax=" +
-                    mCachedBrightnessInfo.brightnessMax);
-            pw.println("  mCachedBrightnessInfo.hbmMode=" + mCachedBrightnessInfo.hbmMode);
-            pw.println("  mCachedBrightnessInfo.highBrightnessTransitionPoint=" +
-                    mCachedBrightnessInfo.highBrightnessTransitionPoint);
+                    mCachedBrightnessInfo.brightnessMax.value);
+            pw.println("  mCachedBrightnessInfo.hbmMode=" + mCachedBrightnessInfo.hbmMode.value);
+            pw.println("  mCachedBrightnessInfo.hbmTransitionPoint=" +
+                    mCachedBrightnessInfo.hbmTransitionPoint.value);
         }
         pw.println("  mDisplayBlanksAfterDozeConfig=" + mDisplayBlanksAfterDozeConfig);
         pw.println("  mBrightnessBucketsInDozeConfig=" + mBrightnessBucketsInDozeConfig);
@@ -2698,11 +2725,31 @@
     }
 
     static class CachedBrightnessInfo {
-        public float brightness;
-        public float adjustedBrightness;
-        public float brightnessMin;
-        public float brightnessMax;
-        public int hbmMode;
-        public float highBrightnessTransitionPoint;
+        public MutableFloat brightness = new MutableFloat(PowerManager.BRIGHTNESS_INVALID_FLOAT);
+        public MutableFloat adjustedBrightness =
+            new MutableFloat(PowerManager.BRIGHTNESS_INVALID_FLOAT);
+        public MutableFloat brightnessMin =
+            new MutableFloat(PowerManager.BRIGHTNESS_INVALID_FLOAT);
+        public MutableFloat brightnessMax =
+            new MutableFloat(PowerManager.BRIGHTNESS_INVALID_FLOAT);
+        public MutableInt hbmMode = new MutableInt(BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF);
+        public MutableFloat hbmTransitionPoint =
+            new MutableFloat(HighBrightnessModeController.HBM_TRANSITION_POINT_INVALID);
+
+        public boolean checkAndSetFloat(MutableFloat mf, float f) {
+            if (mf.value != f) {
+                mf.value = f;
+                return true;
+            }
+            return false;
+        }
+
+        public boolean checkAndSetInt(MutableInt mi, int i) {
+            if (mi.value != i) {
+                mi.value = i;
+                return true;
+            }
+            return false;
+        }
     }
 }
diff --git a/services/core/java/com/android/server/display/WifiDisplayAdapter.java b/services/core/java/com/android/server/display/WifiDisplayAdapter.java
index d2baaf22..d632ee3 100644
--- a/services/core/java/com/android/server/display/WifiDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/WifiDisplayAdapter.java
@@ -147,7 +147,8 @@
                         getContext(), getHandler(), mWifiDisplayListener);
 
                 getContext().registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
-                        new IntentFilter(ACTION_DISCONNECT), null, mHandler);
+                        new IntentFilter(ACTION_DISCONNECT), null, mHandler,
+                        Context.RECEIVER_NOT_EXPORTED);
             }
         });
     }
diff --git a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
index 1461675..9e00f95 100644
--- a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
+++ b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
@@ -509,7 +509,7 @@
      *
      * <pre><code>
      * resolver.registerContentObserver(Settings.Global.getUriFor(
-     *     Settings.Global.AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES), false, observer,
+     *     Settings.Global.AUTOFILL_LOGGING_LEVEL), false, observer,
      *     UserHandle.USER_ALL);
      * </code></pre>
      *
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 3d04037..261aa32 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -347,6 +347,7 @@
     private static native boolean nativeEnableSensor(long ptr, int deviceId, int sensorType,
             int samplingPeriodUs, int maxBatchReportLatencyUs);
     private static native void nativeDisableSensor(long ptr, int deviceId, int sensorType);
+    private static native void nativeCancelCurrentTouch(long ptr);
 
     // Maximum number of milliseconds to wait for input event injection.
     private static final int INJECTION_TIMEOUT_MILLIS = 30 * 1000;
@@ -2510,6 +2511,16 @@
     }
 
     @Override
+    public void cancelCurrentTouch() {
+        if (!checkCallingPermission(android.Manifest.permission.MONITOR_INPUT,
+                "cancelCurrentTouch()")) {
+            throw new SecurityException("Requires MONITOR_INPUT permission");
+        }
+
+        nativeCancelCurrentTouch(mPtr);
+    }
+
+    @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
 
diff --git a/services/core/java/com/android/server/input/InputShellCommand.java b/services/core/java/com/android/server/input/InputShellCommand.java
index 9fa6fad..773dc68 100644
--- a/services/core/java/com/android/server/input/InputShellCommand.java
+++ b/services/core/java/com/android/server/input/InputShellCommand.java
@@ -560,7 +560,12 @@
         sleep(duration);
 
         for (KeyEvent event: events) {
-            injectKeyEventAsync(KeyEvent.changeAction(event, KeyEvent.ACTION_UP));
+            final int keyCode = event.getKeyCode();
+            final KeyEvent upEvent = new KeyEvent(now, now, KeyEvent.ACTION_UP, keyCode,
+                    0, metaState, KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /*scancode*/, 0 /*flags*/,
+                    inputSource);
+            injectKeyEventAsync(upEvent);
+            metaState &= ~MODIFIER.getOrDefault(keyCode, 0);
         }
     }
 
diff --git a/services/core/java/com/android/server/inputmethod/ImfLock.java b/services/core/java/com/android/server/inputmethod/ImfLock.java
new file mode 100644
index 0000000..612c14f
--- /dev/null
+++ b/services/core/java/com/android/server/inputmethod/ImfLock.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.inputmethod;
+
+/**
+ * The implicit lock of this class serves as the global lock for
+ * the {@link InputMethodManagerService} and its controllers,
+ * which contain the main logic of the input method framework (IMF).
+ *
+ * <p>
+ * This lock can be used as follows in code:
+ * <pre>
+ * synchronized (ImfLock.class) {
+ *   ...
+ * }
+ * </pre>
+ *
+ * <p>
+ * For annotations, you can use a similar syntax:
+ * <pre>
+ * &#64;GuardedBy("ImfLock.class")
+ * myMethodDeclaration() {
+ *   ...
+ * }
+ * </pre>
+ */
+final class ImfLock {
+    private ImfLock() {
+        // no instances
+    }
+}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
index c5dc23e..220d790 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
@@ -72,16 +72,16 @@
     @NonNull private final WindowManagerInternal mWindowManagerInternal;
     @NonNull private final Resources mRes;
 
-    private long mLastBindTime;
-    private boolean mHasConnection;
-    @Nullable private String mCurId;
-    @Nullable private String mSelectedMethodId;
-    @Nullable private Intent mCurIntent;
-    @Nullable private IInputMethod mCurMethod;
-    private int mCurMethodUid = Process.INVALID_UID;
-    private IBinder mCurToken;
-    private int mCurSeq;
-    private boolean mVisibleBound;
+    @GuardedBy("ImfLock.class") private long mLastBindTime;
+    @GuardedBy("ImfLock.class") private boolean mHasConnection;
+    @GuardedBy("ImfLock.class") @Nullable private String mCurId;
+    @GuardedBy("ImfLock.class") @Nullable private String mSelectedMethodId;
+    @GuardedBy("ImfLock.class") @Nullable private Intent mCurIntent;
+    @GuardedBy("ImfLock.class") @Nullable private IInputMethod mCurMethod;
+    @GuardedBy("ImfLock.class") private int mCurMethodUid = Process.INVALID_UID;
+    @GuardedBy("ImfLock.class") private IBinder mCurToken;
+    @GuardedBy("ImfLock.class") private int mCurSeq;
+    @GuardedBy("ImfLock.class") private boolean mVisibleBound;
     private boolean mSupportsStylusHw;
 
     /**
@@ -146,6 +146,7 @@
      * Time that we last initiated a bind to the input method, to determine
      * if we should try to disconnect and reconnect to it.
      */
+    @GuardedBy("ImfLock.class")
     long getLastBindTime() {
         return mLastBindTime;
     }
@@ -154,6 +155,7 @@
      * Set to true if our ServiceConnection is currently actively bound to
      * a service (whether or not we have gotten its IBinder back yet).
      */
+    @GuardedBy("ImfLock.class")
     boolean hasConnection() {
         return mHasConnection;
     }
@@ -166,6 +168,7 @@
      *
      * @see #getSelectedMethodId()
      */
+    @GuardedBy("ImfLock.class")
     @Nullable
     String getCurId() {
         return mCurId;
@@ -184,11 +187,13 @@
      *
      * @see #getCurId()
      */
+    @GuardedBy("ImfLock.class")
     @Nullable
     String getSelectedMethodId() {
         return mSelectedMethodId;
     }
 
+    @GuardedBy("ImfLock.class")
     void setSelectedMethodId(@Nullable String selectedMethodId) {
         mSelectedMethodId = selectedMethodId;
     }
@@ -197,6 +202,7 @@
      * The token we have made for the currently active input method, to
      * identify it in the future.
      */
+    @GuardedBy("ImfLock.class")
     IBinder getCurToken() {
         return mCurToken;
     }
@@ -204,6 +210,7 @@
     /**
      * The Intent used to connect to the current input method.
      */
+    @GuardedBy("ImfLock.class")
     @Nullable
     Intent getCurIntent() {
         return mCurIntent;
@@ -213,6 +220,7 @@
      * The current binding sequence number, incremented every time there is
      * a new bind performed.
      */
+    @GuardedBy("ImfLock.class")
     int getSequenceNumber() {
         return mCurSeq;
     }
@@ -221,6 +229,7 @@
      * Increase the current binding sequence number by one.
      * Reset to 1 on overflow.
      */
+    @GuardedBy("ImfLock.class")
     void advanceSequenceNumber() {
         mCurSeq += 1;
         if (mCurSeq <= 0) {
@@ -232,6 +241,7 @@
      * If non-null, this is the input method service we are currently connected
      * to.
      */
+    @GuardedBy("ImfLock.class")
     @Nullable
     IInputMethod getCurMethod() {
         return mCurMethod;
@@ -240,6 +250,7 @@
     /**
      * If not {@link Process#INVALID_UID}, then the UID of {@link #getCurIntent()}.
      */
+    @GuardedBy("ImfLock.class")
     int getCurMethodUid() {
         return mCurMethodUid;
     }
@@ -247,6 +258,7 @@
     /**
      * Indicates whether {@link #mVisibleConnection} is currently in use.
      */
+    @GuardedBy("ImfLock.class")
     boolean isVisibleBound() {
         return mVisibleBound;
     }
@@ -254,11 +266,12 @@
     /**
      * Used to bring IME service up to visible adjustment while it is being shown.
      */
+    @GuardedBy("ImfLock.class")
     private final ServiceConnection mVisibleConnection = new ServiceConnection() {
         @Override public void onBindingDied(ComponentName name) {
-            synchronized (mMethodMap) {
+            synchronized (ImfLock.class) {
                 if (mVisibleBound) {
-                    unbindVisibleConnectionLocked();
+                    unbindVisibleConnection();
                 }
             }
         }
@@ -273,17 +286,18 @@
     /**
      * Used to bind the IME while it is not currently being shown.
      */
+    @GuardedBy("ImfLock.class")
     private final ServiceConnection mMainConnection = new ServiceConnection() {
         @Override
         public void onServiceConnected(ComponentName name, IBinder service) {
             Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.onServiceConnected");
-            synchronized (mMethodMap) {
+            synchronized (ImfLock.class) {
                 if (mCurIntent != null && name.equals(mCurIntent.getComponent())) {
                     mCurMethod = IInputMethod.Stub.asInterface(service);
-                    updateCurrentMethodUidLocked();
+                    updateCurrentMethodUid();
                     if (mCurToken == null) {
                         Slog.w(TAG, "Service connected without a token!");
-                        unbindCurrentMethodLocked();
+                        unbindCurrentMethod();
                         Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
                         return;
                     }
@@ -304,8 +318,8 @@
             Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
         }
 
-        @GuardedBy("mMethodMap")
-        private void updateCurrentMethodUidLocked() {
+        @GuardedBy("ImfLock.class")
+        private void updateCurrentMethodUid() {
             final String curMethodPackage = mCurIntent.getComponent().getPackageName();
             final int curMethodUid = mPackageManagerInternal.getPackageUid(
                     curMethodPackage, 0 /* flags */, mSettings.getCurrentUserId());
@@ -330,7 +344,7 @@
             // refreshed when this method is called back.  Running
             //    adb install -r <APK that implements the current IME>
             // would be a good way to trigger such a situation.
-            synchronized (mMethodMap) {
+            synchronized (ImfLock.class) {
                 if (DEBUG) {
                     Slog.v(TAG, "Service disconnected: " + name + " mCurIntent=" + mCurIntent);
                 }
@@ -339,7 +353,7 @@
                     // We consider this to be a new bind attempt, since the system
                     // should now try to restart the service for us.
                     mLastBindTime = SystemClock.uptimeMillis();
-                    clearCurMethodAndSessionsLocked();
+                    clearCurMethodAndSessions();
                     mService.clearInputShowRequestLocked();
                     mService.unbindCurrentClientLocked(UnbindReason.DISCONNECT_IME);
                 }
@@ -347,35 +361,35 @@
         }
     };
 
-    @GuardedBy("mMethodMap")
-    void unbindCurrentMethodLocked() {
+    @GuardedBy("ImfLock.class")
+    void unbindCurrentMethod() {
         if (mVisibleBound) {
-            unbindVisibleConnectionLocked();
+            unbindVisibleConnection();
         }
 
         if (mHasConnection) {
-            unbindMainConnectionLocked();
+            unbindMainConnection();
         }
 
         if (mCurToken != null) {
-            removeCurrentTokenLocked();
+            removeCurrentToken();
             mService.resetSystemUiLocked();
         }
 
         mCurId = null;
-        clearCurMethodAndSessionsLocked();
+        clearCurMethodAndSessions();
     }
 
-    @GuardedBy("mMethodMap")
-    private void clearCurMethodAndSessionsLocked() {
+    @GuardedBy("ImfLock.class")
+    private void clearCurMethodAndSessions() {
         mService.clearClientSessionsLocked();
         mCurMethod = null;
         mCurMethodUid = Process.INVALID_UID;
     }
 
-    @GuardedBy("mMethodMap")
-    private void removeCurrentTokenLocked() {
-        int curTokenDisplayId = mService.getCurTokenDisplayId();
+    @GuardedBy("ImfLock.class")
+    private void removeCurrentToken() {
+        int curTokenDisplayId = mService.getCurTokenDisplayIdLocked();
 
         if (DEBUG) {
             Slog.v(TAG,
@@ -386,9 +400,9 @@
         mCurToken = null;
     }
 
-    @GuardedBy("mMethodMap")
+    @GuardedBy("ImfLock.class")
     @NonNull
-    InputBindResult bindCurrentMethodLocked() {
+    InputBindResult bindCurrentMethod() {
         InputMethodInfo info = mMethodMap.get(mSelectedMethodId);
         if (info == null) {
             throw new IllegalArgumentException("Unknown id: " + mSelectedMethodId);
@@ -396,11 +410,11 @@
 
         mCurIntent = createImeBindingIntent(info.getComponent());
 
-        if (bindCurrentInputMethodServiceMainConnectionLocked()) {
+        if (bindCurrentInputMethodServiceMainConnection()) {
             mCurId = info.getId();
             mLastBindTime = SystemClock.uptimeMillis();
 
-            addFreshWindowTokenLocked();
+            addFreshWindowToken();
             return new InputBindResult(
                     InputBindResult.ResultCode.SUCCESS_WAITING_IME_BINDING,
                     null, null, mCurId, mCurSeq, false);
@@ -424,12 +438,12 @@
         return intent;
     }
 
-    @GuardedBy("mMethodMap")
-    private void addFreshWindowTokenLocked() {
-        int displayIdToShowIme = mService.getDisplayIdToShowIme();
+    @GuardedBy("ImfLock.class")
+    private void addFreshWindowToken() {
+        int displayIdToShowIme = mService.getDisplayIdToShowImeLocked();
         mCurToken = new Binder();
 
-        mService.setCurTokenDisplayId(displayIdToShowIme);
+        mService.setCurTokenDisplayIdLocked(displayIdToShowIme);
 
         try {
             if (DEBUG) {
@@ -444,20 +458,20 @@
         }
     }
 
-    @GuardedBy("mMethodMap")
-    private void unbindMainConnectionLocked() {
+    @GuardedBy("ImfLock.class")
+    private void unbindMainConnection() {
         mContext.unbindService(mMainConnection);
         mHasConnection = false;
     }
 
-    @GuardedBy("mMethodMap")
-    void unbindVisibleConnectionLocked() {
+    @GuardedBy("ImfLock.class")
+    void unbindVisibleConnection() {
         mContext.unbindService(mVisibleConnection);
         mVisibleBound = false;
     }
 
-    @GuardedBy("mMethodMap")
-    private boolean bindCurrentInputMethodServiceLocked(ServiceConnection conn, int flags) {
+    @GuardedBy("ImfLock.class")
+    private boolean bindCurrentInputMethodService(ServiceConnection conn, int flags) {
         if (mCurIntent == null || conn == null) {
             Slog.e(TAG, "--- bind failed: service = " + mCurIntent + ", conn = " + conn);
             return false;
@@ -466,16 +480,16 @@
                 new UserHandle(mSettings.getCurrentUserId()));
     }
 
-    @GuardedBy("mMethodMap")
-    private boolean bindCurrentInputMethodServiceVisibleConnectionLocked() {
-        mVisibleBound = bindCurrentInputMethodServiceLocked(mVisibleConnection,
+    @GuardedBy("ImfLock.class")
+    private boolean bindCurrentInputMethodServiceVisibleConnection() {
+        mVisibleBound = bindCurrentInputMethodService(mVisibleConnection,
                 IME_VISIBLE_BIND_FLAGS);
         return mVisibleBound;
     }
 
-    @GuardedBy("mMethodMap")
-    private boolean bindCurrentInputMethodServiceMainConnectionLocked() {
-        mHasConnection = bindCurrentInputMethodServiceLocked(mMainConnection,
+    @GuardedBy("ImfLock.class")
+    private boolean bindCurrentInputMethodServiceMainConnection() {
+        mHasConnection = bindCurrentInputMethodService(mMainConnection,
                 mImeConnectionBindFlags);
         return mHasConnection;
     }
@@ -486,27 +500,36 @@
      * <p>
      * Performs a rebind if no binding is achieved in {@link #TIME_TO_RECONNECT} milliseconds.
      */
-    @GuardedBy("mMethodMap")
-    void setCurrentMethodVisibleLocked() {
+    @GuardedBy("ImfLock.class")
+    void setCurrentMethodVisible() {
         if (mCurMethod != null) {
-            if (DEBUG) Slog.d(TAG, "setCurrentMethodVisibleLocked: mCurToken=" + mCurToken);
+            if (DEBUG) Slog.d(TAG, "setCurrentMethodVisible: mCurToken=" + mCurToken);
             if (mHasConnection && !mVisibleBound) {
-                bindCurrentInputMethodServiceVisibleConnectionLocked();
+                bindCurrentInputMethodServiceVisibleConnection();
             }
             return;
         }
 
+        // No IME is currently connected. Reestablish the main connection.
+        if (!mHasConnection) {
+            if (DEBUG) {
+                Slog.d(TAG, "Cannot show input: no IME bound. Rebinding.");
+            }
+            bindCurrentMethod();
+            return;
+        }
+
         long bindingDuration = SystemClock.uptimeMillis() - mLastBindTime;
-        if (mHasConnection && bindingDuration >= TIME_TO_RECONNECT) {
+        if (bindingDuration >= TIME_TO_RECONNECT) {
             // The client has asked to have the input method shown, but
             // we have been sitting here too long with a connection to the
             // service and no interface received, so let's disconnect/connect
             // to try to prod things along.
             EventLog.writeEvent(EventLogTags.IMF_FORCE_RECONNECT_IME, getSelectedMethodId(),
                     bindingDuration, 1);
-            Slog.w(TAG, "Force disconnect/connect to the IME in setCurrentMethodVisibleLocked()");
-            unbindMainConnectionLocked();
-            bindCurrentInputMethodServiceMainConnectionLocked();
+            Slog.w(TAG, "Force disconnect/connect to the IME in setCurrentMethodVisible()");
+            unbindMainConnection();
+            bindCurrentInputMethodServiceMainConnection();
         } else {
             if (DEBUG) {
                 Slog.d(TAG, "Can't show input: connection = " + mHasConnection + ", time = "
@@ -518,10 +541,10 @@
     /**
      * Remove the binding needed for the IME to be shown.
      */
-    @GuardedBy("mMethodMap")
-    void setCurrentMethodNotVisibleLocked() {
+    @GuardedBy("ImfLock.class")
+    void setCurrentMethodNotVisible() {
         if (mVisibleBound) {
-            unbindVisibleConnectionLocked();
+            unbindVisibleConnection();
         }
     }
 }
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index da3729d..c87dc89 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -149,6 +149,7 @@
 import com.android.internal.compat.IPlatformCompat;
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.infra.AndroidFuture;
+import com.android.internal.inputmethod.DirectBootAwareness;
 import com.android.internal.inputmethod.IInputContentUriToken;
 import com.android.internal.inputmethod.IInputMethodPrivilegedOperations;
 import com.android.internal.inputmethod.ImeTracing;
@@ -261,6 +262,16 @@
     private static final String ACTION_SHOW_INPUT_METHOD_PICKER =
             "com.android.server.inputmethod.InputMethodManagerService.SHOW_INPUT_METHOD_PICKER";
 
+    /**
+     * When set, {@link #startInputUncheckedLocked} will return
+     * {@link InputBindResult#NO_EDITOR} instead of starting an IME connection
+     * unless {@link StartInputFlags#IS_TEXT_EDITOR} is set. This behavior overrides
+     * {@link LayoutParams#SOFT_INPUT_STATE_VISIBLE SOFT_INPUT_STATE_VISIBLE} and
+     * {@link LayoutParams#SOFT_INPUT_STATE_ALWAYS_VISIBLE SOFT_INPUT_STATE_ALWAYS_VISIBLE}
+     * starting from {@link android.os.Build.VERSION_CODES#P}.
+     */
+    private final boolean mPreventImeStartupUnlessTextEditor;
+
     @UserIdInt
     private int mLastSwitchUserId;
 
@@ -292,9 +303,7 @@
     @Nullable
     private AudioManagerInternal mAudioManagerInternal = null;
 
-
-    // All known input methods.  mMethodMap also serves as the global
-    // lock for this class.
+    // All known input methods.
     final ArrayList<InputMethodInfo> mMethodList = new ArrayList<>();
     final ArrayMap<String, InputMethodInfo> mMethodMap = new ArrayMap<>();
     final InputMethodSubtypeSwitchingController mSwitchingController;
@@ -302,18 +311,18 @@
     /**
      * Tracks how many times {@link #mMethodMap} was updated.
      */
-    @GuardedBy("mMethodMap")
+    @GuardedBy("ImfLock.class")
     private int mMethodMapUpdateCount = 0;
 
     /**
      * The display id for which the latest startInput was called.
      */
-    @GuardedBy("mMethodMap")
-    int getDisplayIdToShowIme() {
+    @GuardedBy("ImfLock.class")
+    int getDisplayIdToShowImeLocked() {
         return mDisplayIdToShowIme;
     }
 
-    @GuardedBy("mMethodMap")
+    @GuardedBy("ImfLock.class")
     private int mDisplayIdToShowIme = INVALID_DISPLAY;
 
     // Ongoing notification
@@ -399,7 +408,7 @@
         }
     }
 
-    @GuardedBy("mMethodMap")
+    @GuardedBy("ImfLock.class")
     final ArrayMap<IBinder, ClientState> mClients = new ArrayMap<>();
 
     /**
@@ -415,17 +424,19 @@
      * <p>This can be transiently {@code null} when the system is re-initializing input method
      * settings, e.g., the system locale is just changed.</p>
      *
-     * <p>Note that {@link InputMethodBindingController#getCurId()} is used to track which IME is
-     * being connected to {@link InputMethodManagerService}.</p>
+     * <p>Note that {@link InputMethodBindingController#getCurId()} is used to track which IME
+     * is being connected to {@link InputMethodManagerService}.</p>
      *
      * @see InputMethodBindingController#getCurId()
      */
+    @GuardedBy("ImfLock.class")
     @Nullable
-    private String getSelectedMethodId() {
+    String getSelectedMethodIdLocked() {
         return mBindingController.getSelectedMethodId();
     }
 
-    private void setSelectedMethodId(@Nullable String selectedMethodId) {
+    @GuardedBy("ImfLock.class")
+    private void setSelectedMethodIdLocked(@Nullable String selectedMethodId) {
         mBindingController.setSelectedMethodId(selectedMethodId);
     }
 
@@ -433,7 +444,8 @@
      * The current binding sequence number, incremented every time there is
      * a new bind performed.
      */
-    private int getSequenceNumber() {
+    @GuardedBy("ImfLock.class")
+    private int getSequenceNumberLocked() {
         return mBindingController.getSequenceNumber();
     }
 
@@ -441,7 +453,8 @@
      * Increase the current binding sequence number by one.
      * Reset to 1 on overflow.
      */
-    private void advanceSequenceNumber() {
+    @GuardedBy("ImfLock.class")
+    private void advanceSequenceNumberLocked() {
         mBindingController.advanceSequenceNumber();
     }
 
@@ -500,10 +513,11 @@
      *
      * <p>This can be {@code null} when no input method is connected.</p>
      *
-     * @see #getSelectedMethodId()
+     * @see #getSelectedMethodIdLocked()
      */
+    @GuardedBy("ImfLock.class")
     @Nullable
-    private String getCurId() {
+    private String getCurIdLocked() {
         return mBindingController.getCurId();
     }
 
@@ -521,7 +535,8 @@
      * Set to true if our ServiceConnection is currently actively bound to
      * a service (whether or not we have gotten its IBinder back yet).
      */
-    private boolean hasConnection() {
+    @GuardedBy("ImfLock.class")
+    private boolean hasConnectionLocked() {
         return mBindingController.hasConnection();
     }
 
@@ -553,8 +568,9 @@
     /**
      * The Intent used to connect to the current input method.
      */
+    @GuardedBy("ImfLock.class")
     @Nullable
-    private Intent getCurIntent() {
+    private Intent getCurIntentLocked() {
         return mBindingController.getCurIntent();
     }
 
@@ -562,27 +578,31 @@
      * The token we have made for the currently active input method, to
      * identify it in the future.
      */
-    private IBinder getCurToken() {
+    @GuardedBy("ImfLock.class")
+    private IBinder getCurTokenLocked() {
         return mBindingController.getCurToken();
     }
 
     /**
      * The displayId of current active input method.
      */
-    int getCurTokenDisplayId() {
+    @GuardedBy("ImfLock.class")
+    int getCurTokenDisplayIdLocked() {
         return mCurTokenDisplayId;
     }
 
-    void setCurTokenDisplayId(int curTokenDisplayId) {
+    @GuardedBy("ImfLock.class")
+    void setCurTokenDisplayIdLocked(int curTokenDisplayId) {
         mCurTokenDisplayId = curTokenDisplayId;
     }
 
-    int mCurTokenDisplayId = INVALID_DISPLAY;
+    @GuardedBy("ImfLock.class")
+    private int mCurTokenDisplayId = INVALID_DISPLAY;
 
     /**
      * The host input token of the current active input method.
      */
-    @GuardedBy("mMethodMap")
+    @GuardedBy("ImfLock.class")
     @Nullable
     private IBinder mCurHostInputToken;
 
@@ -598,15 +618,17 @@
      * If non-null, this is the input method service we are currently connected
      * to.
      */
+    @GuardedBy("ImfLock.class")
     @Nullable
-    private IInputMethod getCurMethod() {
+    private IInputMethod getCurMethodLocked() {
         return mBindingController.getCurMethod();
     }
 
     /**
-     * If not {@link Process#INVALID_UID}, then the UID of {@link #getCurIntent()}.
+     * If not {@link Process#INVALID_UID}, then the UID of {@link #getCurIntentLocked()}.
      */
-    private int getCurMethodUid() {
+    @GuardedBy("ImfLock.class")
+    private int getCurMethodUidLocked() {
         return mBindingController.getCurMethodUid();
     }
 
@@ -614,7 +636,8 @@
      * Time that we last initiated a bind to the input method, to determine
      * if we should try to disconnect and reconnect to it.
      */
-    private long getLastBindTime() {
+    @GuardedBy("ImfLock.class")
+    private long getLastBindTimeLocked() {
         return mBindingController.getLastBindTime();
     }
 
@@ -657,7 +680,7 @@
      * </dd>
      * </dl>
      * <em>Do not update this value outside of {@link #setImeWindowStatus(IBinder, int, int)} and
-     * {@link InputMethodBindingController#unbindCurrentMethodLocked()}.</em>
+     * {@link InputMethodBindingController#unbindCurrentMethod()}.</em>
      */
     int mImeWindowVis;
 
@@ -740,7 +763,7 @@
         }
     }
 
-    @GuardedBy("mMethodMap")
+    @GuardedBy("ImfLock.class")
     private final WeakHashMap<IBinder, IBinder> mImeTargetWindowMap = new WeakHashMap<>();
 
     private static final class SoftInputShowHideHistory {
@@ -848,7 +871,7 @@
      * {@link InputMethodManager#showSoftInput(View, int)}.
      * This map tracks origin of showSoftInput requests.
      */
-    @GuardedBy("mMethodMap")
+    @GuardedBy("ImfLock.class")
     private final WeakHashMap<IBinder, IBinder> mShowRequestWindowMap = new WeakHashMap<>();
 
     /**
@@ -856,7 +879,7 @@
      * {@link InputMethodManager#hideSoftInputFromWindow(IBinder, int)}.
      * This map tracks origin of hideSoftInput requests.
      */
-    @GuardedBy("mMethodMap")
+    @GuardedBy("ImfLock.class")
     private final WeakHashMap<IBinder, IBinder> mHideRequestWindowMap = new WeakHashMap<>();
 
     /**
@@ -1013,11 +1036,11 @@
         }
     }
 
-    @GuardedBy("mMethodMap")
+    @GuardedBy("ImfLock.class")
     @NonNull
     private final StartInputHistory mStartInputHistory = new StartInputHistory();
 
-    @GuardedBy("mMethodMap")
+    @GuardedBy("ImfLock.class")
     @NonNull
     private final SoftInputShowHideHistory mSoftInputShowHideHistory =
             new SoftInputShowHideHistory();
@@ -1035,7 +1058,7 @@
             super(handler);
         }
 
-        @GuardedBy("mMethodMap")
+        @GuardedBy("ImfLock.class")
         public void registerContentObserverLocked(@UserIdInt int userId) {
             if (mRegistered && mUserId == userId) {
                 return;
@@ -1067,7 +1090,7 @@
                     Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD);
             final Uri accessibilityRequestingNoImeUri = Settings.Secure.getUriFor(
                     Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE);
-            synchronized (mMethodMap) {
+            synchronized (ImfLock.class) {
                 if (showImeUri.equals(uri)) {
                     mMenuController.updateKeyboardFromSettingsLocked();
                 } else if (accessibilityRequestingNoImeUri.equals(uri)) {
@@ -1173,7 +1196,7 @@
      * <p>Caution: This method must not be called when system is not ready.</p>
      */
     void onActionLocaleChanged() {
-        synchronized (mMethodMap) {
+        synchronized (ImfLock.class) {
             final LocaleList possibleNewLocale = mRes.getConfiguration().getLocales();
             if (possibleNewLocale != null && possibleNewLocale.equals(mLastSystemLocales)) {
                 return;
@@ -1195,7 +1218,7 @@
          * dynamically unless the entire package is updated, which also always triggers package
          * rescanning.</p>
          */
-        @GuardedBy("mMethodMap")
+        @GuardedBy("ImfLock.class")
         final private ArraySet<String> mKnownImePackageNames = new ArraySet<>();
 
         /**
@@ -1218,17 +1241,17 @@
          */
         private boolean mImePackageAppeared = false;
 
-        @GuardedBy("mMethodMap")
+        @GuardedBy("ImfLock.class")
         void clearKnownImePackageNamesLocked() {
             mKnownImePackageNames.clear();
         }
 
-        @GuardedBy("mMethodMap")
+        @GuardedBy("ImfLock.class")
         final void addKnownImePackageNameLocked(@NonNull String packageName) {
             mKnownImePackageNames.add(packageName);
         }
 
-        @GuardedBy("mMethodMap")
+        @GuardedBy("ImfLock.class")
         private boolean isChangingPackagesOfCurrentUserLocked() {
             final int userId = getChangingUserId();
             final boolean retval = userId == mSettings.getCurrentUserId();
@@ -1242,7 +1265,7 @@
 
         @Override
         public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) {
-            synchronized (mMethodMap) {
+            synchronized (ImfLock.class) {
                 if (!isChangingPackagesOfCurrentUserLocked()) {
                     return false;
                 }
@@ -1330,7 +1353,7 @@
             mImePackageAppeared = false;
         }
 
-        @GuardedBy("mMethodMap")
+        @GuardedBy("ImfLock.class")
         private boolean shouldRebuildInputMethodListLocked() {
             // This method is guaranteed to be called only by getRegisteredHandler().
 
@@ -1354,7 +1377,7 @@
         }
 
         private void onFinishPackageChangesInternal() {
-            synchronized (mMethodMap) {
+            synchronized (ImfLock.class) {
                 if (!isChangingPackagesOfCurrentUserLocked()) {
                     return;
                 }
@@ -1477,7 +1500,7 @@
 
         @Override
         public void run() {
-            synchronized (mService.mMethodMap) {
+            synchronized (ImfLock.class) {
                 if (mService.mUserSwitchHandlerTask != this) {
                     // This task was already canceled before it is handled here. So do nothing.
                     return;
@@ -1494,7 +1517,7 @@
      * a handler callback.  This needs to be set and unset only within the lock.
      */
     @Nullable
-    @GuardedBy("mMethodMap")
+    @GuardedBy("ImfLock.class")
     private UserSwitchHandlerTask mUserSwitchHandlerTask;
 
     public static final class Lifecycle extends SystemService {
@@ -1516,7 +1539,7 @@
         @Override
         public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
             // Called on ActivityManager thread.
-            synchronized (mService.mMethodMap) {
+            synchronized (ImfLock.class) {
                 mService.scheduleSwitchUserTaskLocked(to.getUserIdentifier(),
                         /* clientToBeReset= */ null);
             }
@@ -1542,7 +1565,7 @@
     }
 
     void onUnlockUser(@UserIdInt int userId) {
-        synchronized(mMethodMap) {
+        synchronized (ImfLock.class) {
             final int currentUserId = mSettings.getCurrentUserId();
             if (DEBUG) {
                 Slog.d(TAG, "onUnlockUser: userId=" + userId + " curUserId=" + currentUserId);
@@ -1559,7 +1582,7 @@
         }
     }
 
-    @GuardedBy("mMethodMap")
+    @GuardedBy("ImfLock.class")
     void scheduleSwitchUserTaskLocked(@UserIdInt int userId,
             @Nullable IInputMethodClient clientToBeReset) {
         if (mUserSwitchHandlerTask != null) {
@@ -1648,12 +1671,14 @@
                 mSettings, context);
         mMenuController = new InputMethodMenuController(this);
         mBindingController = new InputMethodBindingController(this);
+        mPreventImeStartupUnlessTextEditor = mRes.getBoolean(
+                com.android.internal.R.bool.config_preventImeStartupUnlessTextEditor);
     }
 
-    @GuardedBy("mMethodMap")
+    @GuardedBy("ImfLock.class")
     private void resetDefaultImeLocked(Context context) {
         // Do not reset the default (current) IME when it is a 3rd-party IME
-        String selectedMethodId = getSelectedMethodId();
+        String selectedMethodId = getSelectedMethodIdLocked();
         if (selectedMethodId != null && !mMethodMap.get(selectedMethodId).isSystem()) {
             return;
         }
@@ -1670,7 +1695,7 @@
         setSelectedInputMethodAndSubtypeLocked(defIm, NOT_A_SUBTYPE_ID, false);
     }
 
-    @GuardedBy("mMethodMap")
+    @GuardedBy("ImfLock.class")
     private void switchUserOnHandlerLocked(@UserIdInt int newUserId,
             IInputMethodClient clientToBeReset) {
         if (DEBUG) Slog.d(TAG, "Switching user stage 1/3. newUserId=" + newUserId
@@ -1756,7 +1781,7 @@
     }
 
     public void systemRunning(StatusBarManagerService statusBar) {
-        synchronized (mMethodMap) {
+        synchronized (ImfLock.class) {
             if (DEBUG) {
                 Slog.d(TAG, "--- systemReady");
             }
@@ -1812,7 +1837,7 @@
     // Check whether or not this is a valid IPC. Assumes an IPC is valid when either
     // 1) it comes from the system process
     // 2) the calling process' user id is identical to the current user id IMMS thinks.
-    @GuardedBy("mMethodMap")
+    @GuardedBy("ImfLock.class")
     private boolean calledFromValidUserLocked() {
         final int uid = Binder.getCallingUid();
         final int userId = UserHandle.getUserId(uid);
@@ -1856,12 +1881,12 @@
      * @param token The window token given to the input method when it was started.
      * @return true if and only if non-null valid token is specified.
      */
-    @GuardedBy("mMethodMap")
+    @GuardedBy("ImfLock.class")
     private boolean calledWithValidTokenLocked(@NonNull IBinder token) {
         if (token == null) {
             throw new InvalidParameterException("token must not be null.");
         }
-        if (token != getCurToken()) {
+        if (token != getCurTokenLocked()) {
             Slog.e(TAG, "Ignoring " + Debug.getCaller() + " due to an invalid token."
                     + " uid:" + Binder.getCallingUid() + " token:" + token);
             return false;
@@ -1869,13 +1894,13 @@
         return true;
     }
 
-    @Override
-    public List<InputMethodInfo> getInputMethodList(@UserIdInt int userId) {
+    private List<InputMethodInfo> getInputMethodListInternal(@UserIdInt int userId,
+            @DirectBootAwareness int directBootAwareness) {
         if (UserHandle.getCallingUserId() != userId) {
             mContext.enforceCallingPermission(
                     Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
         }
-        synchronized (mMethodMap) {
+        synchronized (ImfLock.class) {
             final int[] resolvedUserIds = InputMethodUtils.resolveUserId(userId,
                     mSettings.getCurrentUserId(), null);
             if (resolvedUserIds.length != 1) {
@@ -1883,7 +1908,7 @@
             }
             final long ident = Binder.clearCallingIdentity();
             try {
-                return getInputMethodListLocked(resolvedUserIds[0]);
+                return getInputMethodListLocked(resolvedUserIds[0], directBootAwareness);
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
@@ -1891,12 +1916,23 @@
     }
 
     @Override
+    public List<InputMethodInfo> getInputMethodList(@UserIdInt int userId) {
+        return getInputMethodListInternal(userId, DirectBootAwareness.AUTO);
+    }
+
+    @Override
+    public List<InputMethodInfo> getAwareLockedInputMethodList(@UserIdInt int userId,
+            @DirectBootAwareness int directBootAwareness) {
+        return getInputMethodListInternal(userId, directBootAwareness);
+    }
+
+    @Override
     public List<InputMethodInfo> getEnabledInputMethodList(@UserIdInt int userId) {
         if (UserHandle.getCallingUserId() != userId) {
             mContext.enforceCallingPermission(
                     Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
         }
-        synchronized (mMethodMap) {
+        synchronized (ImfLock.class) {
             final int[] resolvedUserIds = InputMethodUtils.resolveUserId(userId,
                     mSettings.getCurrentUserId(), null);
             if (resolvedUserIds.length != 1) {
@@ -1911,10 +1947,12 @@
         }
     }
 
-    @GuardedBy("mMethodMap")
-    private List<InputMethodInfo> getInputMethodListLocked(@UserIdInt int userId) {
+    @GuardedBy("ImfLock.class")
+    private List<InputMethodInfo> getInputMethodListLocked(@UserIdInt int userId,
+            @DirectBootAwareness int directBootAwareness) {
         final ArrayList<InputMethodInfo> methodList;
-        if (userId == mSettings.getCurrentUserId()) {
+        if (userId == mSettings.getCurrentUserId()
+                && directBootAwareness == DirectBootAwareness.AUTO) {
             // Create a copy.
             methodList = new ArrayList<>(mMethodList);
         } else {
@@ -1924,12 +1962,12 @@
                     new ArrayMap<>();
             AdditionalSubtypeUtils.load(additionalSubtypeMap, userId);
             queryInputMethodServicesInternal(mContext, userId, additionalSubtypeMap, methodMap,
-                    methodList);
+                    methodList, directBootAwareness);
         }
         return methodList;
     }
 
-    @GuardedBy("mMethodMap")
+    @GuardedBy("ImfLock.class")
     private List<InputMethodInfo> getEnabledInputMethodListLocked(@UserIdInt int userId) {
         if (userId == mSettings.getCurrentUserId()) {
             return mSettings.getEnabledInputMethodListLocked();
@@ -1940,18 +1978,19 @@
         return settings.getEnabledInputMethodListLocked();
     }
 
-    @GuardedBy("mMethodMap")
+    @GuardedBy("ImfLock.class")
     private void onCreateInlineSuggestionsRequestLocked(@UserIdInt int userId,
             InlineSuggestionsRequestInfo requestInfo, IInlineSuggestionsRequestCallback callback) {
-        final InputMethodInfo imi = mMethodMap.get(getSelectedMethodId());
+        final InputMethodInfo imi = mMethodMap.get(getSelectedMethodIdLocked());
         try {
-            IInputMethod curMethod = getCurMethod();
+            IInputMethod curMethod = getCurMethodLocked();
             if (userId == mSettings.getCurrentUserId() && imi != null
                     && imi.isInlineSuggestionsEnabled() && curMethod != null) {
                 executeOrSendMessage(curMethod,
                         mCaller.obtainMessageOOO(MSG_INLINE_SUGGESTIONS_REQUEST, curMethod,
                                 requestInfo, new InlineSuggestionsRequestCallbackDecorator(callback,
-                                        imi.getPackageName(), mCurTokenDisplayId, getCurToken(),
+                                        imi.getPackageName(), mCurTokenDisplayId,
+                                        getCurTokenLocked(),
                                         this)));
             } else {
                 callback.onInlineSuggestionsUnsupported();
@@ -2047,7 +2086,7 @@
      * @param hostInputToken the host input token of the current active input method
      */
     void setCurHostInputToken(@NonNull IBinder callerImeToken, @Nullable IBinder hostInputToken) {
-        synchronized (mMethodMap) {
+        synchronized (ImfLock.class) {
             if (!calledWithValidTokenLocked(callerImeToken)) {
                 return;
             }
@@ -2066,7 +2105,7 @@
     public List<InputMethodSubtype> getEnabledInputMethodSubtypeList(String imiId,
             boolean allowsImplicitlySelectedSubtypes) {
         final int callingUserId = UserHandle.getCallingUserId();
-        synchronized (mMethodMap) {
+        synchronized (ImfLock.class) {
             final int[] resolvedUserIds = InputMethodUtils.resolveUserId(callingUserId,
                     mSettings.getCurrentUserId(), null);
             if (resolvedUserIds.length != 1) {
@@ -2082,12 +2121,12 @@
         }
     }
 
-    @GuardedBy("mMethodMap")
+    @GuardedBy("ImfLock.class")
     private List<InputMethodSubtype> getEnabledInputMethodSubtypeListLocked(String imiId,
             boolean allowsImplicitlySelectedSubtypes, @UserIdInt int userId) {
         if (userId == mSettings.getCurrentUserId()) {
             final InputMethodInfo imi;
-            String selectedMethodId = getSelectedMethodId();
+            String selectedMethodId = getSelectedMethodIdLocked();
             if (imiId == null && selectedMethodId != null) {
                 imi = mMethodMap.get(selectedMethodId);
             } else {
@@ -2137,7 +2176,7 @@
         // actually running.
         final int callerUid = Binder.getCallingUid();
         final int callerPid = Binder.getCallingPid();
-        synchronized (mMethodMap) {
+        synchronized (ImfLock.class) {
             // TODO: Optimize this linear search.
             final int numClients = mClients.size();
             for (int i = 0; i < numClients; ++i) {
@@ -2170,7 +2209,7 @@
     }
 
     void removeClient(IInputMethodClient client) {
-        synchronized (mMethodMap) {
+        synchronized (ImfLock.class) {
             ClientState cs = mClients.remove(client.asBinder());
             if (cs != null) {
                 client.asBinder().unlinkToDeath(cs.clientDeathRecipient, 0);
@@ -2180,7 +2219,7 @@
                             mCurFocusedWindow, 0, null, SoftInputShowHideReason.HIDE_REMOVE_CLIENT);
                     if (mBoundToMethod) {
                         mBoundToMethod = false;
-                        IInputMethod curMethod = getCurMethod();
+                        IInputMethod curMethod = getCurMethodLocked();
                         if (curMethod != null) {
                             executeOrSendMessage(curMethod, mCaller.obtainMessageO(
                                     MSG_UNBIND_INPUT, curMethod));
@@ -2204,14 +2243,14 @@
          }
     }
 
-    @GuardedBy("mMethodMap")
+    @GuardedBy("ImfLock.class")
     void unbindCurrentClientLocked(@UnbindReason int unbindClientReason) {
         if (mCurClient != null) {
             if (DEBUG) Slog.v(TAG, "unbindCurrentInputLocked: client="
                     + mCurClient.client.asBinder());
             if (mBoundToMethod) {
                 mBoundToMethod = false;
-                IInputMethod curMethod = getCurMethod();
+                IInputMethod curMethod = getCurMethodLocked();
                 if (curMethod != null) {
                     executeOrSendMessage(curMethod, mCaller.obtainMessageO(
                             MSG_UNBIND_INPUT, curMethod));
@@ -2221,7 +2260,8 @@
             scheduleSetActiveToClient(mCurClient, false /* active */, false /* fullscreen */,
                     false /* reportToImeController */);
             executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIIO(
-                    MSG_UNBIND_CLIENT, getSequenceNumber(), unbindClientReason, mCurClient.client));
+                    MSG_UNBIND_CLIENT, getSequenceNumberLocked(), unbindClientReason,
+                    mCurClient.client));
             mCurClient.sessionRequested = false;
             mCurClient = null;
 
@@ -2229,13 +2269,13 @@
         }
     }
 
-    @GuardedBy("mMethodMap")
+    @GuardedBy("ImfLock.class")
     void clearInputShowRequestLocked() {
         mShowRequested = mInputShown;
         mInputShown = false;
     }
 
-    @GuardedBy("mMethodMap")
+    @GuardedBy("ImfLock.class")
     private int getImeShowFlagsLocked() {
         int flags = 0;
         if (mShowForced) {
@@ -2247,7 +2287,7 @@
         return flags;
     }
 
-    @GuardedBy("mMethodMap")
+    @GuardedBy("ImfLock.class")
     private int getAppShowFlagsLocked() {
         int flags = 0;
         if (mShowForced) {
@@ -2258,22 +2298,23 @@
         return flags;
     }
 
-    @GuardedBy("mMethodMap")
+    @GuardedBy("ImfLock.class")
     @NonNull
     InputBindResult attachNewInputLocked(@StartInputReason int startInputReason, boolean initial) {
         if (!mBoundToMethod) {
-            IInputMethod curMethod = getCurMethod();
+            IInputMethod curMethod = getCurMethodLocked();
             executeOrSendMessage(curMethod, mCaller.obtainMessageOO(
                     MSG_BIND_INPUT, curMethod, mCurClient.binding));
             mBoundToMethod = true;
         }
 
         final Binder startInputToken = new Binder();
-        final StartInputInfo info = new StartInputInfo(mSettings.getCurrentUserId(), getCurToken(),
-                mCurTokenDisplayId, getCurId(), startInputReason, !initial,
+        final StartInputInfo info = new StartInputInfo(mSettings.getCurrentUserId(),
+                getCurTokenLocked(),
+                mCurTokenDisplayId, getCurIdLocked(), startInputReason, !initial,
                 UserHandle.getUserId(mCurClient.uid), mCurClient.selfReportedDisplayId,
                 mCurFocusedWindow, mCurAttribute, mCurFocusedWindowSoftInputMode,
-                getSequenceNumber());
+                getSequenceNumberLocked());
         mImeTargetWindowMap.put(startInputToken, mCurFocusedWindow);
         mStartInputHistory.addEntry(info);
 
@@ -2284,7 +2325,7 @@
         // INTERACT_ACROSS_USERS(_FULL) permissions, which is actually almost always the case.
         if (mSettings.getCurrentUserId() == UserHandle.getUserId(mCurClient.uid)) {
             mPackageManagerInternal.grantImplicitAccess(mSettings.getCurrentUserId(),
-                    null /* intent */, UserHandle.getAppId(getCurMethodUid()), mCurClient.uid,
+                    null /* intent */, UserHandle.getAppId(getCurMethodUidLocked()), mCurClient.uid,
                     true /* direct */);
         }
 
@@ -2298,22 +2339,22 @@
                     SoftInputShowHideReason.ATTACH_NEW_INPUT);
         }
 
-        String curId = getCurId();
+        String curId = getCurIdLocked();
         final InputMethodInfo curInputMethodInfo = mMethodMap.get(curId);
         final boolean suppressesSpellChecker =
                 curInputMethodInfo != null && curInputMethodInfo.suppressesSpellChecker();
         return new InputBindResult(InputBindResult.ResultCode.SUCCESS_WITH_IME_SESSION,
                 session.session, (session.channel != null ? session.channel.dup() : null),
-                curId, getSequenceNumber(), suppressesSpellChecker);
+                curId, getSequenceNumberLocked(), suppressesSpellChecker);
     }
 
-    @GuardedBy("mMethodMap")
+    @GuardedBy("ImfLock.class")
     @NonNull
     InputBindResult startInputUncheckedLocked(@NonNull ClientState cs, IInputContext inputContext,
             @NonNull EditorInfo attribute, @StartInputFlags int startInputFlags,
-            @StartInputReason int startInputReason) {
+            @StartInputReason int startInputReason, int unverifiedTargetSdkVersion) {
         // If no method is currently selected, do nothing.
-        String selectedMethodId = getSelectedMethodId();
+        String selectedMethodId = getSelectedMethodIdLocked();
         if (selectedMethodId == null) {
             return InputBindResult.NO_IME;
         }
@@ -2323,7 +2364,7 @@
             // party code.
             return new InputBindResult(
                     InputBindResult.ResultCode.ERROR_SYSTEM_NOT_READY,
-                    null, null, selectedMethodId, getSequenceNumber(), false);
+                    null, null, selectedMethodId, getSequenceNumberLocked(), false);
         }
 
         if (!InputMethodUtils.checkIfPackageBelongsToUid(mAppOpsManager, cs.uid,
@@ -2355,15 +2396,27 @@
         }
 
         // Bump up the sequence for this client and attach it.
-        advanceSequenceNumber();
+        advanceSequenceNumberLocked();
         mCurClient = cs;
         mCurInputContext = inputContext;
         mCurAttribute = attribute;
 
+        // If configured, we want to avoid starting up the IME if it is not supposed to be showing
+        if (mPreventImeStartupUnlessTextEditor
+                && !InputMethodUtils.isSoftInputModeStateVisibleAllowed(unverifiedTargetSdkVersion,
+                startInputFlags)
+                && !mShowRequested) {
+            if (DEBUG) {
+                Slog.d(TAG, "Avoiding IME startup and unbinding current input method.");
+            }
+            mBindingController.unbindCurrentMethod();
+            return InputBindResult.NO_EDITOR;
+        }
+
         // Check if the input method is changing.
         // We expect the caller has already verified that the client is allowed to access this
         // display ID.
-        if (isSelectedMethodBound()) {
+        if (isSelectedMethodBoundLocked()) {
             if (cs.curSession != null) {
                 // Fast case: if we are already connected to the input method,
                 // then just return it.
@@ -2377,18 +2430,19 @@
             }
         }
 
-        mBindingController.unbindCurrentMethodLocked();
+        mBindingController.unbindCurrentMethod();
 
-        return mBindingController.bindCurrentMethodLocked();
+        return mBindingController.bindCurrentMethod();
     }
 
-    private boolean isSelectedMethodBound() {
-        String curId = getCurId();
-        return curId != null && curId.equals(getSelectedMethodId())
+    @GuardedBy("ImfLock.class")
+    private boolean isSelectedMethodBoundLocked() {
+        String curId = getCurIdLocked();
+        return curId != null && curId.equals(getSelectedMethodIdLocked())
                 && mDisplayIdToShowIme == mCurTokenDisplayId;
     }
 
-    @GuardedBy("mMethodMap")
+    @GuardedBy("ImfLock.class")
     private void prepareClientSwitchLocked(ClientState cs) {
         // If the client is changing, we need to switch over to the new
         // one.
@@ -2400,19 +2454,19 @@
         }
     }
 
-    @GuardedBy("mMethodMap")
+    @GuardedBy("ImfLock.class")
     @Nullable
     private InputBindResult tryReuseConnectionLocked(@NonNull ClientState cs) {
-        if (hasConnection()) {
-            if (getCurMethod() != null) {
+        if (hasConnectionLocked()) {
+            if (getCurMethodLocked() != null) {
                 // Return to client, and we will get back with it when
                 // we have had a session made for it.
                 requestClientSessionLocked(cs);
                 return new InputBindResult(
                         InputBindResult.ResultCode.SUCCESS_WAITING_IME_SESSION,
-                        null, null, getCurId(), getSequenceNumber(), false);
+                        null, null, getCurIdLocked(), getSequenceNumberLocked(), false);
             } else {
-                long bindingDuration = SystemClock.uptimeMillis() - getLastBindTime();
+                long bindingDuration = SystemClock.uptimeMillis() - getLastBindTimeLocked();
                 if (bindingDuration < TIME_TO_RECONNECT) {
                     // In this case we have connected to the service, but
                     // don't yet have its interface.  If it hasn't been too
@@ -2423,10 +2477,10 @@
                     // to see if we can get back in touch with the service.
                     return new InputBindResult(
                             InputBindResult.ResultCode.SUCCESS_WAITING_IME_BINDING,
-                            null, null, getCurId(), getSequenceNumber(), false);
+                            null, null, getCurIdLocked(), getSequenceNumberLocked(), false);
                 } else {
                     EventLog.writeEvent(EventLogTags.IMF_FORCE_RECONNECT_IME,
-                            getSelectedMethodId(), bindingDuration, 0);
+                            getSelectedMethodIdLocked(), bindingDuration, 0);
                 }
             }
         }
@@ -2473,13 +2527,13 @@
 
     void onSessionCreated(IInputMethod method, IInputMethodSession session,
             InputChannel channel) {
-        synchronized (mMethodMap) {
+        synchronized (ImfLock.class) {
             if (mUserSwitchHandlerTask != null) {
                 // We have a pending user-switching task so it's better to just ignore this session.
                 channel.dispose();
                 return;
             }
-            IInputMethod curMethod = getCurMethod();
+            IInputMethod curMethod = getCurMethodLocked();
             if (curMethod != null && method != null
                     && curMethod.asBinder() == method.asBinder()) {
                 if (mCurClient != null) {
@@ -2501,7 +2555,7 @@
         channel.dispose();
     }
 
-    @GuardedBy("mMethodMap")
+    @GuardedBy("ImfLock.class")
     void resetSystemUiLocked() {
         // Set IME window status as invisible when unbinding current method.
         mImeWindowVis = 0;
@@ -2511,14 +2565,14 @@
         mCurHostInputToken = null;
     }
 
-    @GuardedBy("mMethodMap")
+    @GuardedBy("ImfLock.class")
     void resetCurrentMethodAndClientLocked(@UnbindReason int unbindClientReason) {
-        setSelectedMethodId(null);
-        mBindingController.unbindCurrentMethodLocked();
+        setSelectedMethodIdLocked(null);
+        mBindingController.unbindCurrentMethod();
         unbindCurrentClientLocked(unbindClientReason);
     }
 
-    @GuardedBy("mMethodMap")
+    @GuardedBy("ImfLock.class")
     void reRequestCurrentClientSessionLocked() {
         if (mCurClient != null) {
             clearClientSessionLocked(mCurClient);
@@ -2526,27 +2580,27 @@
         }
     }
 
-    @GuardedBy("mMethodMap")
+    @GuardedBy("ImfLock.class")
     void requestClientSessionLocked(ClientState cs) {
         if (!cs.sessionRequested) {
             if (DEBUG) Slog.v(TAG, "Creating new session for client " + cs);
             InputChannel[] channels = InputChannel.openInputChannelPair(cs.toString());
             cs.sessionRequested = true;
-            IInputMethod curMethod = getCurMethod();
+            IInputMethod curMethod = getCurMethodLocked();
             executeOrSendMessage(curMethod, mCaller.obtainMessageOOO(
                     MSG_CREATE_SESSION, curMethod, channels[1],
                     new MethodCallback(this, curMethod, channels[0])));
         }
     }
 
-    @GuardedBy("mMethodMap")
+    @GuardedBy("ImfLock.class")
     void clearClientSessionLocked(ClientState cs) {
         finishSessionLocked(cs.curSession);
         cs.curSession = null;
         cs.sessionRequested = false;
     }
 
-    @GuardedBy("mMethodMap")
+    @GuardedBy("ImfLock.class")
     private void finishSessionLocked(SessionState sessionState) {
         if (sessionState != null) {
             if (sessionState.session != null) {
@@ -2565,9 +2619,9 @@
         }
     }
 
-    @GuardedBy("mMethodMap")
+    @GuardedBy("ImfLock.class")
     void clearClientSessionsLocked() {
-        if (getCurMethod() != null) {
+        if (getCurMethodLocked() != null) {
             final int numClients = mClients.size();
             for (int i = 0; i < numClients; ++i) {
                 clearClientSessionLocked(mClients.valueAt(i));
@@ -2584,7 +2638,7 @@
     @BinderThread
     private void updateStatusIcon(@NonNull IBinder token, String packageName,
             @DrawableRes int iconId) {
-        synchronized (mMethodMap) {
+        synchronized (ImfLock.class) {
             if (!calledWithValidTokenLocked(token)) {
                 return;
             }
@@ -2618,14 +2672,14 @@
         }
     }
 
-    @GuardedBy("mMethodMap")
+    @GuardedBy("ImfLock.class")
     private void hideStatusBarIconLocked() {
         if (mStatusBar != null) {
             mStatusBar.setIconVisibility(mSlotIme, false);
         }
     }
 
-    @GuardedBy("mMethodMap")
+    @GuardedBy("ImfLock.class")
     private boolean shouldShowImeSwitcherLocked(int visibility) {
         if (!mShowOngoingImeSwitcherForPhones) return false;
         if (mMenuController.getSwitchingDialogLocked() != null) return false;
@@ -2694,7 +2748,7 @@
     private void setImeWindowStatus(@NonNull IBinder token, int vis, int backDisposition) {
         final int topFocusedDisplayId = mWindowManagerInternal.getTopFocusedDisplayId();
 
-        synchronized (mMethodMap) {
+        synchronized (ImfLock.class) {
             if (!calledWithValidTokenLocked(token)) {
                 return;
             }
@@ -2729,7 +2783,7 @@
 
     @BinderThread
     private void reportStartInput(@NonNull IBinder token, IBinder startInputToken) {
-        synchronized (mMethodMap) {
+        synchronized (ImfLock.class) {
             if (!calledWithValidTokenLocked(token)) {
                 return;
             }
@@ -2742,7 +2796,7 @@
     }
 
     private void updateImeWindowStatus(boolean disableImeIcon) {
-        synchronized (mMethodMap) {
+        synchronized (ImfLock.class) {
             if (disableImeIcon) {
                 updateSystemUiLocked(0, mBackDisposition);
             } else {
@@ -2751,15 +2805,15 @@
         }
     }
 
-    @GuardedBy("mMethodMap")
+    @GuardedBy("ImfLock.class")
     void updateSystemUiLocked() {
         updateSystemUiLocked(mImeWindowVis, mBackDisposition);
     }
 
     // Caution! This method is called in this class. Handle multi-user carefully
-    @GuardedBy("mMethodMap")
+    @GuardedBy("ImfLock.class")
     private void updateSystemUiLocked(int vis, int backDisposition) {
-        if (getCurToken() == null) {
+        if (getCurTokenLocked() == null) {
             return;
         }
         if (DEBUG) {
@@ -2784,10 +2838,10 @@
             // mImeWindowVis should be updated before calling shouldShowImeSwitcherLocked().
             final boolean needsToShowImeSwitcher = shouldShowImeSwitcherLocked(vis);
             if (mStatusBar != null) {
-                mStatusBar.setImeWindowStatus(mCurTokenDisplayId, getCurToken(), vis,
+                mStatusBar.setImeWindowStatus(mCurTokenDisplayId, getCurTokenLocked(), vis,
                         backDisposition, needsToShowImeSwitcher);
             }
-            final InputMethodInfo imi = mMethodMap.get(getSelectedMethodId());
+            final InputMethodInfo imi = mMethodMap.get(getSelectedMethodIdLocked());
             if (imi != null && needsToShowImeSwitcher) {
                 // Used to load label
                 final CharSequence title = mRes.getText(
@@ -2826,13 +2880,13 @@
         }
     }
 
-    @GuardedBy("mMethodMap")
+    @GuardedBy("ImfLock.class")
     void updateFromSettingsLocked(boolean enabledMayChange) {
         updateInputMethodsFromSettingsLocked(enabledMayChange);
         mMenuController.updateKeyboardFromSettingsLocked();
     }
 
-    @GuardedBy("mMethodMap")
+    @GuardedBy("ImfLock.class")
     void updateInputMethodsFromSettingsLocked(boolean enabledMayChange) {
         if (enabledMayChange) {
             List<InputMethodInfo> enabled = mSettings.getEnabledInputMethodListLocked();
@@ -2887,7 +2941,7 @@
 
     }
 
-    @GuardedBy("mMethodMap")
+    @GuardedBy("ImfLock.class")
     void setInputMethodLocked(String id, int subtypeId) {
         InputMethodInfo info = mMethodMap.get(id);
         if (info == null) {
@@ -2895,7 +2949,7 @@
         }
 
         // See if we need to notify a subtype change within the same IME.
-        if (id.equals(getSelectedMethodId())) {
+        if (id.equals(getSelectedMethodIdLocked())) {
             final int subtypeCount = info.getSubtypeCount();
             if (subtypeCount <= 0) {
                 return;
@@ -2916,7 +2970,7 @@
             }
             if (newSubtype != oldSubtype) {
                 setSelectedInputMethodAndSubtypeLocked(info, subtypeId, true);
-                IInputMethod curMethod = getCurMethod();
+                IInputMethod curMethod = getCurMethodLocked();
                 if (curMethod != null) {
                     try {
                         updateSystemUiLocked(mImeWindowVis, mBackDisposition);
@@ -2938,7 +2992,7 @@
             // mCurMethodId should be updated after setSelectedInputMethodAndSubtypeLocked()
             // because mCurMethodId is stored as a history in
             // setSelectedInputMethodAndSubtypeLocked().
-            setSelectedMethodId(id);
+            setSelectedMethodIdLocked(id);
 
             if (LocalServices.getService(ActivityManagerInternal.class).isSystemReady()) {
                 Intent intent = new Intent(Intent.ACTION_INPUT_METHOD_CHANGED);
@@ -2959,7 +3013,7 @@
         int uid = Binder.getCallingUid();
         ImeTracing.getInstance().triggerManagerServiceDump(
                 "InputMethodManagerService#showSoftInput");
-        synchronized (mMethodMap) {
+        synchronized (ImfLock.class) {
             if (!calledFromValidUserLocked()) {
                 return false;
             }
@@ -2995,7 +3049,7 @@
     public void reportPerceptibleAsync(IBinder windowToken, boolean perceptible) {
         Objects.requireNonNull(windowToken, "windowToken must not be null");
         int uid = Binder.getCallingUid();
-        synchronized (mMethodMap) {
+        synchronized (ImfLock.class) {
             if (!calledFromValidUserLocked()) {
                 return;
             }
@@ -3012,7 +3066,7 @@
         }
     }
 
-    @GuardedBy("mMethodMap")
+    @GuardedBy("ImfLock.class")
     boolean showCurrentInputLocked(IBinder windowToken, int flags, ResultReceiver resultReceiver,
             @SoftInputShowHideReason int reason) {
         mShowRequested = true;
@@ -3031,12 +3085,12 @@
             return false;
         }
 
-        mBindingController.setCurrentMethodVisibleLocked();
-        if (getCurMethod() != null) {
+        mBindingController.setCurrentMethodVisible();
+        if (getCurMethodLocked() != null) {
             // create a placeholder token for IMS so that IMS cannot inject windows into client app.
             Binder showInputToken = new Binder();
             mShowRequestWindowMap.put(showInputToken, windowToken);
-            IInputMethod curMethod = getCurMethod();
+            IInputMethod curMethod = getCurMethodLocked();
             executeOrSendMessage(curMethod, mCaller.obtainMessageIIOOO(MSG_SHOW_SOFT_INPUT,
                     getImeShowFlagsLocked(), reason, curMethod, resultReceiver,
                     showInputToken));
@@ -3053,7 +3107,7 @@
         int uid = Binder.getCallingUid();
         ImeTracing.getInstance().triggerManagerServiceDump(
                 "InputMethodManagerService#hideSoftInput");
-        synchronized (mMethodMap) {
+        synchronized (ImfLock.class) {
             if (!InputMethodManagerService.this.calledFromValidUserLocked()) {
                 return false;
             }
@@ -3090,7 +3144,7 @@
         }
     }
 
-    @GuardedBy("mMethodMap")
+    @GuardedBy("ImfLock.class")
     boolean hideCurrentInputLocked(IBinder windowToken, int flags, ResultReceiver resultReceiver,
             @SoftInputShowHideReason int reason) {
         if ((flags&InputMethodManager.HIDE_IMPLICIT_ONLY) != 0
@@ -3111,7 +3165,7 @@
         // since Android Eclair.  That's why we need to accept IMM#hideSoftInput() even when only
         // IMMS#InputShown indicates that the software keyboard is shown.
         // TODO: Clean up, IMMS#mInputShown, IMMS#mImeWindowVis and mShowRequested.
-        IInputMethod curMethod = getCurMethod();
+        IInputMethod curMethod = getCurMethodLocked();
         final boolean shouldHideSoftInput = (curMethod != null) && (mInputShown
                 || (mImeWindowVis & InputMethodService.IME_ACTIVE) != 0);
         boolean res;
@@ -3128,7 +3182,7 @@
         } else {
             res = false;
         }
-        mBindingController.setCurrentMethodNotVisibleLocked();
+        mBindingController.setCurrentMethodNotVisible();
         mInputShown = false;
         mShowRequested = false;
         mShowExplicitlyRequested = false;
@@ -3184,7 +3238,7 @@
                 userId = callingUserId;
             }
             final InputBindResult result;
-            synchronized (mMethodMap) {
+            synchronized (ImfLock.class) {
                 final long ident = Binder.clearCallingIdentity();
                 try {
                     result = startInputOrWindowGainedFocusInternalLocked(startInputReason,
@@ -3209,7 +3263,7 @@
         }
     }
 
-    @GuardedBy("mMethodMap")
+    @GuardedBy("ImfLock.class")
     @NonNull
     private InputBindResult startInputOrWindowGainedFocusInternalLocked(
             @StartInputReason int startInputReason, IInputMethodClient client,
@@ -3302,7 +3356,7 @@
             }
             if (attribute != null) {
                 return startInputUncheckedLocked(cs, inputContext, attribute, startInputFlags,
-                        startInputReason);
+                        startInputReason, unverifiedTargetSdkVersion);
             }
             return new InputBindResult(
                     InputBindResult.ResultCode.SUCCESS_REPORT_WINDOW_FOCUS_ONLY,
@@ -3343,7 +3397,7 @@
         if (isTextEditor && attribute != null
                 && shouldRestoreImeVisibility(windowToken, softInputMode)) {
             res = startInputUncheckedLocked(cs, inputContext, attribute, startInputFlags,
-                    startInputReason);
+                    startInputReason, unverifiedTargetSdkVersion);
             showCurrentInputLocked(windowToken, InputMethodManager.SHOW_IMPLICIT, null,
                     SoftInputShowHideReason.SHOW_RESTORE_IME_VISIBILITY);
             return res;
@@ -3367,7 +3421,7 @@
                         // Note that we can trust client's display ID as long as it matches
                         // to the display ID obtained from the window.
                         if (cs.selfReportedDisplayId != mCurTokenDisplayId) {
-                            mBindingController.unbindCurrentMethodLocked();
+                            mBindingController.unbindCurrentMethod();
                         }
                     }
                 } else if (isTextEditor && doAutoShow
@@ -3382,7 +3436,7 @@
                     if (DEBUG) Slog.v(TAG, "Unspecified window will show input");
                     if (attribute != null) {
                         res = startInputUncheckedLocked(cs, inputContext, attribute,
-                                startInputFlags, startInputReason);
+                                startInputFlags, startInputReason, unverifiedTargetSdkVersion);
                         didStart = true;
                     }
                     showCurrentInputLocked(windowToken, InputMethodManager.SHOW_IMPLICIT, null,
@@ -3413,7 +3467,7 @@
                             unverifiedTargetSdkVersion, startInputFlags)) {
                         if (attribute != null) {
                             res = startInputUncheckedLocked(cs, inputContext, attribute,
-                                    startInputFlags, startInputReason);
+                                    startInputFlags, startInputReason, unverifiedTargetSdkVersion);
                             didStart = true;
                         }
                         showCurrentInputLocked(windowToken, InputMethodManager.SHOW_IMPLICIT, null,
@@ -3432,7 +3486,7 @@
                     if (!sameWindowFocused) {
                         if (attribute != null) {
                             res = startInputUncheckedLocked(cs, inputContext, attribute,
-                                    startInputFlags, startInputReason);
+                                    startInputFlags, startInputReason, unverifiedTargetSdkVersion);
                             didStart = true;
                         }
                         showCurrentInputLocked(windowToken, InputMethodManager.SHOW_IMPLICIT, null,
@@ -3461,7 +3515,7 @@
                     }
                 }
                 res = startInputUncheckedLocked(cs, inputContext, attribute, startInputFlags,
-                        startInputReason);
+                        startInputReason, unverifiedTargetSdkVersion);
             } else {
                 res = InputBindResult.NULL_EDITOR_INFO;
             }
@@ -3482,17 +3536,17 @@
         return mWindowManagerInternal.shouldRestoreImeVisibility(windowToken);
     }
 
-    @GuardedBy("mMethodMap")
+    @GuardedBy("ImfLock.class")
     private boolean canShowInputMethodPickerLocked(IInputMethodClient client) {
         // TODO(yukawa): multi-display support.
         final int uid = Binder.getCallingUid();
         if (mCurFocusedWindowClient != null && client != null
                 && mCurFocusedWindowClient.client.asBinder() == client.asBinder()) {
             return true;
-        } else if (getCurIntent() != null && InputMethodUtils.checkIfPackageBelongsToUid(
+        } else if (getCurIntentLocked() != null && InputMethodUtils.checkIfPackageBelongsToUid(
                 mAppOpsManager,
                 uid,
-                getCurIntent().getComponent().getPackageName())) {
+                getCurIntentLocked().getComponent().getPackageName())) {
             return true;
         }
         return false;
@@ -3501,7 +3555,7 @@
     @Override
     public void showInputMethodPickerFromClient(IInputMethodClient client,
             int auxiliarySubtypeMode) {
-        synchronized (mMethodMap) {
+        synchronized (ImfLock.class) {
             if (!calledFromValidUserLocked()) {
                 return;
             }
@@ -3538,14 +3592,14 @@
      * A test API for CTS to make sure that the input method menu is showing.
      */
     public boolean isInputMethodPickerShownForTest() {
-        synchronized(mMethodMap) {
+        synchronized (ImfLock.class) {
             return mMenuController.isisInputMethodPickerShownForTestLocked();
         }
     }
 
     @BinderThread
     private void setInputMethod(@NonNull IBinder token, String id) {
-        synchronized (mMethodMap) {
+        synchronized (ImfLock.class) {
             if (!calledWithValidTokenLocked(token)) {
                 return;
             }
@@ -3556,7 +3610,7 @@
     @BinderThread
     private void setInputMethodAndSubtype(@NonNull IBinder token, String id,
             InputMethodSubtype subtype) {
-        synchronized (mMethodMap) {
+        synchronized (ImfLock.class) {
             if (!calledWithValidTokenLocked(token)) {
                 return;
             }
@@ -3573,19 +3627,19 @@
     @Override
     public void showInputMethodAndSubtypeEnablerFromClient(
             IInputMethodClient client, String inputMethodId) {
-        synchronized (mMethodMap) {
+        synchronized (ImfLock.class) {
             // TODO(yukawa): Should we verify the display ID?
             if (!calledFromValidUserLocked()) {
                 return;
             }
-            executeOrSendMessage(getCurMethod(), mCaller.obtainMessageO(
+            executeOrSendMessage(getCurMethodLocked(), mCaller.obtainMessageO(
                     MSG_SHOW_IM_SUBTYPE_ENABLER, inputMethodId));
         }
     }
 
     @BinderThread
     private boolean switchToPreviousInputMethod(@NonNull IBinder token) {
-        synchronized (mMethodMap) {
+        synchronized (ImfLock.class) {
             if (!calledWithValidTokenLocked(token)) {
                 return false;
             }
@@ -3599,7 +3653,7 @@
             String targetLastImiId = null;
             int subtypeId = NOT_A_SUBTYPE_ID;
             if (lastIme != null && lastImi != null) {
-                final boolean imiIdIsSame = lastImi.getId().equals(getSelectedMethodId());
+                final boolean imiIdIsSame = lastImi.getId().equals(getSelectedMethodIdLocked());
                 final int lastSubtypeHash = Integer.parseInt(lastIme.second);
                 final int currentSubtypeHash = mCurrentSubtype == null ? NOT_A_SUBTYPE_ID
                         : mCurrentSubtype.hashCode();
@@ -3645,7 +3699,7 @@
             if (!TextUtils.isEmpty(targetLastImiId)) {
                 if (DEBUG) {
                     Slog.d(TAG, "Switch to: " + lastImi.getId() + ", " + lastIme.second
-                            + ", from: " + getSelectedMethodId() + ", " + subtypeId);
+                            + ", from: " + getSelectedMethodIdLocked() + ", " + subtypeId);
                 }
                 setInputMethodWithSubtypeIdLocked(token, targetLastImiId, subtypeId);
                 return true;
@@ -3657,12 +3711,12 @@
 
     @BinderThread
     private boolean switchToNextInputMethod(@NonNull IBinder token, boolean onlyCurrentIme) {
-        synchronized (mMethodMap) {
+        synchronized (ImfLock.class) {
             if (!calledWithValidTokenLocked(token)) {
                 return false;
             }
             final ImeSubtypeListItem nextSubtype = mSwitchingController.getNextInputMethodLocked(
-                    onlyCurrentIme, mMethodMap.get(getSelectedMethodId()), mCurrentSubtype);
+                    onlyCurrentIme, mMethodMap.get(getSelectedMethodIdLocked()), mCurrentSubtype);
             if (nextSubtype == null) {
                 return false;
             }
@@ -3674,12 +3728,12 @@
 
     @BinderThread
     private boolean shouldOfferSwitchingToNextInputMethod(@NonNull IBinder token) {
-        synchronized (mMethodMap) {
+        synchronized (ImfLock.class) {
             if (!calledWithValidTokenLocked(token)) {
                 return false;
             }
             final ImeSubtypeListItem nextSubtype = mSwitchingController.getNextInputMethodLocked(
-                    false /* onlyCurrentIme */, mMethodMap.get(getSelectedMethodId()),
+                    false /* onlyCurrentIme */, mMethodMap.get(getSelectedMethodIdLocked()),
                     mCurrentSubtype);
             if (nextSubtype == null) {
                 return false;
@@ -3690,7 +3744,7 @@
 
     @Override
     public InputMethodSubtype getLastInputMethodSubtype() {
-        synchronized (mMethodMap) {
+        synchronized (ImfLock.class) {
             if (!calledFromValidUserLocked()) {
                 return null;
             }
@@ -3728,7 +3782,7 @@
                         + subtype.getLocale() + ", " + subtype.getMode());
             }
         }
-        synchronized (mMethodMap) {
+        synchronized (ImfLock.class) {
             if (!calledFromValidUserLocked()) {
                 return;
             }
@@ -3779,7 +3833,11 @@
     @Override
     public int getInputMethodWindowVisibleHeight() {
         // TODO(yukawa): Should we verify the display ID?
-        return mWindowManagerInternal.getInputMethodWindowVisibleHeight(mCurTokenDisplayId);
+        final int curTokenDisplayId;
+        synchronized (ImfLock.class) {
+            curTokenDisplayId = mCurTokenDisplayId;
+        }
+        return mWindowManagerInternal.getInputMethodWindowVisibleHeight(curTokenDisplayId);
     }
 
     @Override
@@ -3858,7 +3916,7 @@
     public void startImeTrace() {
         ImeTracing.getInstance().startTrace(null /* printwriter */);
         ArrayMap<IBinder, ClientState> clients;
-        synchronized (mMethodMap) {
+        synchronized (ImfLock.class) {
             clients = new ArrayMap<>(mClients);
         }
         for (ClientState state : clients.values()) {
@@ -3877,7 +3935,7 @@
     public void stopImeTrace() {
         ImeTracing.getInstance().stopTrace(null /* printwriter */);
         ArrayMap<IBinder, ClientState> clients;
-        synchronized (mMethodMap) {
+        synchronized (ImfLock.class) {
             clients = new ArrayMap<>(mClients);
         }
         for (ClientState state : clients.values()) {
@@ -3892,10 +3950,10 @@
     }
 
     private void dumpDebug(ProtoOutputStream proto, long fieldId) {
-        synchronized (mMethodMap) {
+        synchronized (ImfLock.class) {
             final long token = proto.start(fieldId);
-            proto.write(CUR_METHOD_ID, getSelectedMethodId());
-            proto.write(CUR_SEQ, getSequenceNumber());
+            proto.write(CUR_METHOD_ID, getSelectedMethodIdLocked());
+            proto.write(CUR_SEQ, getSequenceNumberLocked());
             proto.write(CUR_CLIENT, Objects.toString(mCurClient));
             proto.write(CUR_FOCUSED_WINDOW_NAME,
                     mWindowManagerInternal.getWindowName(mCurFocusedWindow));
@@ -3906,17 +3964,17 @@
             if (mCurAttribute != null) {
                 mCurAttribute.dumpDebug(proto, CUR_ATTRIBUTE);
             }
-            proto.write(CUR_ID, getCurId());
+            proto.write(CUR_ID, getCurIdLocked());
             proto.write(SHOW_REQUESTED, mShowRequested);
             proto.write(SHOW_EXPLICITLY_REQUESTED, mShowExplicitlyRequested);
             proto.write(SHOW_FORCED, mShowForced);
             proto.write(INPUT_SHOWN, mInputShown);
             proto.write(IN_FULLSCREEN_MODE, mInFullscreenMode);
-            proto.write(CUR_TOKEN, Objects.toString(getCurToken()));
+            proto.write(CUR_TOKEN, Objects.toString(getCurTokenLocked()));
             proto.write(CUR_TOKEN_DISPLAY_ID, mCurTokenDisplayId);
             proto.write(SYSTEM_READY, mSystemReady);
             proto.write(LAST_SWITCH_USER_ID, mLastSwitchUserId);
-            proto.write(HAVE_CONNECTION, hasConnection());
+            proto.write(HAVE_CONNECTION, hasConnectionLocked());
             proto.write(BOUND_TO_METHOD, mBoundToMethod);
             proto.write(IS_INTERACTIVE, mIsInteractive);
             proto.write(BACK_DISPOSITION, mBackDisposition);
@@ -3933,15 +3991,15 @@
         if (DEBUG) {
             Slog.d(TAG, "Got the notification of a user action.");
         }
-        synchronized (mMethodMap) {
-            if (getCurToken() != token) {
+        synchronized (ImfLock.class) {
+            if (getCurTokenLocked() != token) {
                 if (DEBUG) {
                     Slog.d(TAG, "Ignoring the user action notification from IMEs that are no longer"
                             + " active.");
                 }
                 return;
             }
-            final InputMethodInfo imi = mMethodMap.get(getSelectedMethodId());
+            final InputMethodInfo imi = mMethodMap.get(getSelectedMethodIdLocked());
             if (imi != null) {
                 mSwitchingController.onUserActionLocked(imi, mCurrentSubtype);
             }
@@ -3951,7 +4009,7 @@
     @BinderThread
     private void applyImeVisibility(IBinder token, IBinder windowToken, boolean setVisible) {
         Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.applyImeVisibility");
-        synchronized (mMethodMap) {
+        synchronized (ImfLock.class) {
             if (!calledWithValidTokenLocked(token)) {
                 return;
             }
@@ -3975,7 +4033,7 @@
         Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
     }
 
-    @GuardedBy("mMethodMap")
+    @GuardedBy("ImfLock.class")
     private void setInputMethodWithSubtypeIdLocked(IBinder token, String id, int subtypeId) {
         if (token == null) {
             if (mContext.checkCallingOrSelfPermission(
@@ -3985,7 +4043,7 @@
                         "Using null token requires permission "
                         + android.Manifest.permission.WRITE_SECURE_SETTINGS);
             }
-        } else if (getCurToken() != token) {
+        } else if (getCurTokenLocked() != token) {
             Slog.w(TAG, "Ignoring setInputMethod of uid " + Binder.getCallingUid()
                     + " token: " + token);
             return;
@@ -4000,6 +4058,7 @@
     }
 
     /** Called right after {@link IInputMethod#showSoftInput}. */
+    @GuardedBy("ImfLock.class")
     private void onShowHideSoftInputRequested(boolean show, IBinder requestToken,
             @SoftInputShowHideReason int reason) {
         final WindowManagerInternal.ImeTargetInfo info =
@@ -4014,7 +4073,7 @@
     @BinderThread
     private void hideMySoftInput(@NonNull IBinder token, int flags) {
         Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.hideMySoftInput");
-        synchronized (mMethodMap) {
+        synchronized (ImfLock.class) {
             if (!calledWithValidTokenLocked(token)) {
                 return;
             }
@@ -4034,7 +4093,7 @@
     @BinderThread
     private void showMySoftInput(@NonNull IBinder token, int flags) {
         Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.showMySoftInput");
-        synchronized (mMethodMap) {
+        synchronized (ImfLock.class) {
             if (!calledWithValidTokenLocked(token)) {
                 return;
             }
@@ -4132,8 +4191,11 @@
                     final IBinder token = (IBinder) args.arg3;
                     ((IInputMethod) args.arg1).showSoftInput(
                             token, msg.arg1 /* flags */, (ResultReceiver) args.arg2);
-                    final IBinder requestToken = mShowRequestWindowMap.get(token);
-                    onShowHideSoftInputRequested(true /* show */, requestToken, reason);
+                    final IBinder requestToken;
+                    synchronized (ImfLock.class) {
+                        requestToken = mShowRequestWindowMap.get(token);
+                        onShowHideSoftInputRequested(true /* show */, requestToken, reason);
+                    }
                 } catch (RemoteException e) {
                 }
                 args.recycle();
@@ -4148,14 +4210,17 @@
                     final IBinder token = (IBinder) args.arg3;
                     ((IInputMethod)args.arg1).hideSoftInput(
                             token, 0 /* flags */, (ResultReceiver) args.arg2);
-                    final IBinder requestToken = mHideRequestWindowMap.get(token);
-                    onShowHideSoftInputRequested(false /* show */, requestToken, reason);
+                    final IBinder requestToken;
+                    synchronized (ImfLock.class) {
+                        requestToken = mHideRequestWindowMap.get(token);
+                        onShowHideSoftInputRequested(false /* show */, requestToken, reason);
+                    }
                 } catch (RemoteException e) {
                 }
                 args.recycle();
                 return true;
             case MSG_HIDE_CURRENT_INPUT_METHOD:
-                synchronized (mMethodMap) {
+                synchronized (ImfLock.class) {
                     final @SoftInputShowHideReason int reason = (int) msg.obj;
                     hideCurrentInputLocked(mCurFocusedWindow, 0, null, reason);
 
@@ -4165,8 +4230,10 @@
                 args = (SomeArgs)msg.obj;
                 try {
                     if (DEBUG) {
-                        Slog.v(TAG, "Sending attach of token: " + args.arg2 + " for display: "
-                                + mCurTokenDisplayId);
+                        synchronized (ImfLock.class) {
+                            Slog.v(TAG, "Sending attach of token: " + args.arg2 + " for display: "
+                                    + mCurTokenDisplayId);
+                        }
                     }
                     final IBinder token = (IBinder) args.arg2;
                     ((IInputMethod) args.arg1).initializeInternal(token,
@@ -4193,7 +4260,7 @@
                 return true;
             }
             case MSG_REMOVE_IME_SURFACE: {
-                synchronized (mMethodMap) {
+                synchronized (ImfLock.class) {
                     try {
                         if (mEnabledSession != null && mEnabledSession.session != null
                                 && !mShowRequested) {
@@ -4206,7 +4273,7 @@
             }
             case MSG_REMOVE_IME_SURFACE_FROM_WINDOW: {
                 IBinder windowToken = (IBinder) msg.obj;
-                synchronized (mMethodMap) {
+                synchronized (ImfLock.class) {
                     try {
                         if (windowToken == mCurFocusedWindow
                                 && mEnabledSession != null && mEnabledSession.session != null) {
@@ -4348,7 +4415,7 @@
     }
 
     private void handleSetInteractive(final boolean interactive) {
-        synchronized (mMethodMap) {
+        synchronized (ImfLock.class) {
             mIsInteractive = interactive;
             updateSystemUiLocked(interactive ? mImeWindowVis : 0, mBackDisposition);
 
@@ -4357,7 +4424,7 @@
                 boolean reportToImeController = false;
                 try {
                     reportToImeController = mPlatformCompat.isChangeEnabledByUid(
-                            FINISH_INPUT_NO_FALLBACK_CONNECTION, getCurMethodUid());
+                            FINISH_INPUT_NO_FALLBACK_CONNECTION, getCurMethodUidLocked());
                 } catch (RemoteException e) {
                 }
                 scheduleSetActiveToClient(mCurClient, mIsInteractive, mInFullscreenMode,
@@ -4372,7 +4439,7 @@
                 active ? 1 : 0, fullscreen ? 1 : 0, reportToImeController ? 1 : 0, 0, state));
     }
 
-    @GuardedBy("mMethodMap")
+    @GuardedBy("ImfLock.class")
     private boolean chooseNewDefaultIMELocked() {
         final InputMethodInfo imi = InputMethodUtils.getMostApplicableDefaultIME(
                 mSettings.getEnabledInputMethodListLocked());
@@ -4389,17 +4456,31 @@
 
     static void queryInputMethodServicesInternal(Context context,
             @UserIdInt int userId, ArrayMap<String, List<InputMethodSubtype>> additionalSubtypeMap,
-            ArrayMap<String, InputMethodInfo> methodMap, ArrayList<InputMethodInfo> methodList) {
+            ArrayMap<String, InputMethodInfo> methodMap, ArrayList<InputMethodInfo> methodList,
+            @DirectBootAwareness int directBootAwareness) {
         methodList.clear();
         methodMap.clear();
 
-        // Note: We do not specify PackageManager.MATCH_ENCRYPTION_* flags here because the default
-        // behavior of PackageManager is exactly what we want.  It by default picks up appropriate
-        // services depending on the unlock state for the specified user.
+        final int directBootAwarenessFlags;
+        switch (directBootAwareness) {
+            case DirectBootAwareness.ANY:
+                directBootAwarenessFlags = PackageManager.MATCH_DIRECT_BOOT_AWARE
+                        | PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
+                break;
+            case DirectBootAwareness.AUTO:
+                directBootAwarenessFlags = PackageManager.MATCH_DIRECT_BOOT_AUTO;
+                break;
+            default:
+                directBootAwarenessFlags = PackageManager.MATCH_DIRECT_BOOT_AUTO;
+                Slog.e(TAG, "Unknown directBootAwareness=" + directBootAwareness
+                        + ". Falling back to DirectBootAwareness.AUTO");
+                break;
+        }
+        final int flags = PackageManager.GET_META_DATA
+                | PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
+                | directBootAwarenessFlags;
         final List<ResolveInfo> services = context.getPackageManager().queryIntentServicesAsUser(
-                new Intent(InputMethod.SERVICE_INTERFACE),
-                PackageManager.GET_META_DATA | PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS,
-                userId);
+                new Intent(InputMethod.SERVICE_INTERFACE), flags, userId);
 
         methodList.ensureCapacity(services.size());
         methodMap.ensureCapacity(services.size());
@@ -4434,7 +4515,7 @@
         }
     }
 
-    @GuardedBy("mMethodMap")
+    @GuardedBy("ImfLock.class")
     void buildInputMethodListLocked(boolean resetDefaultEnabledIme) {
         if (DEBUG) {
             Slog.d(TAG, "--- re-buildInputMethodList reset = " + resetDefaultEnabledIme
@@ -4448,7 +4529,7 @@
         mMyPackageMonitor.clearKnownImePackageNamesLocked();
 
         queryInputMethodServicesInternal(mContext, mSettings.getCurrentUserId(),
-                mAdditionalSubtypeMap, mMethodMap, mMethodList);
+                mAdditionalSubtypeMap, mMethodMap, mMethodList, DirectBootAwareness.AUTO);
 
         // Construct the set of possible IME packages for onPackageChanged() to avoid false
         // negatives when the package state remains to be the same but only the component state is
@@ -4542,7 +4623,7 @@
                 mSettings.getCurrentUserId(), 0 /* unused */, inputMethodList).sendToTarget();
     }
 
-    @GuardedBy("mMethodMap")
+    @GuardedBy("ImfLock.class")
     private void updateDefaultVoiceImeIfNeededLocked() {
         final String systemSpeechRecognizer =
                 mContext.getString(com.android.internal.R.string.config_systemSpeechRecognizer);
@@ -4584,7 +4665,7 @@
             intent.putExtra(Settings.EXTRA_INPUT_METHOD_ID, inputMethodId);
         }
         final int userId;
-        synchronized (mMethodMap) {
+        synchronized (ImfLock.class) {
             userId = mSettings.getCurrentUserId();
         }
         mContext.startActivityAsUser(intent, null, UserHandle.of(userId));
@@ -4608,7 +4689,7 @@
      * @param enabled {@code true} if {@code id} needs to be enabled.
      * @return {@code true} if the IME was previously enabled. {@code false} otherwise.
      */
-    @GuardedBy("mMethodMap")
+    @GuardedBy("ImfLock.class")
     private boolean setInputMethodEnabledLocked(String id, boolean enabled) {
         List<Pair<String, ArrayList<String>>> enabledInputMethodsList = mSettings
                 .getEnabledInputMethodsAndSubtypeListLocked();
@@ -4644,10 +4725,11 @@
         }
     }
 
-    @GuardedBy("mMethodMap")
+    @GuardedBy("ImfLock.class")
     private void setSelectedInputMethodAndSubtypeLocked(InputMethodInfo imi, int subtypeId,
             boolean setSubtypeOnly) {
-        mSettings.saveCurrentInputMethodAndSubtypeToHistory(getSelectedMethodId(), mCurrentSubtype);
+        mSettings.saveCurrentInputMethodAndSubtypeToHistory(getSelectedMethodIdLocked(),
+                mCurrentSubtype);
 
         // Set Subtype here
         if (imi == null || subtypeId < 0) {
@@ -4671,7 +4753,7 @@
         }
     }
 
-    @GuardedBy("mMethodMap")
+    @GuardedBy("ImfLock.class")
     private void resetSelectedInputMethodAndSubtypeLocked(String newDefaultIme) {
         InputMethodInfo imi = mMethodMap.get(newDefaultIme);
         int lastSubtypeId = NOT_A_SUBTYPE_ID;
@@ -4695,7 +4777,7 @@
      */
     @Override
     public InputMethodSubtype getCurrentInputMethodSubtype() {
-        synchronized (mMethodMap) {
+        synchronized (ImfLock.class) {
             // TODO: Make this work even for non-current users?
             if (!calledFromValidUserLocked()) {
                 return null;
@@ -4704,9 +4786,9 @@
         }
     }
 
-    @GuardedBy("mMethodMap")
+    @GuardedBy("ImfLock.class")
     InputMethodSubtype getCurrentInputMethodSubtypeLocked() {
-        String selectedMethodId = getSelectedMethodId();
+        String selectedMethodId = getSelectedMethodIdLocked();
         if (selectedMethodId == null) {
             return null;
         }
@@ -4745,19 +4827,14 @@
         return mCurrentSubtype;
     }
 
-    @Nullable
-    String getCurrentMethodId() {
-        return getSelectedMethodId();
-    }
-
     private List<InputMethodInfo> getInputMethodListAsUser(@UserIdInt int userId) {
-        synchronized (mMethodMap) {
-            return getInputMethodListLocked(userId);
+        synchronized (ImfLock.class) {
+            return getInputMethodListLocked(userId, DirectBootAwareness.AUTO);
         }
     }
 
     private List<InputMethodInfo> getEnabledInputMethodListAsUser(@UserIdInt int userId) {
-        synchronized (mMethodMap) {
+        synchronized (ImfLock.class) {
             return getEnabledInputMethodListLocked(userId);
         }
     }
@@ -4765,7 +4842,7 @@
     private void onCreateInlineSuggestionsRequest(@UserIdInt int userId,
             InlineSuggestionsRequestInfo requestInfo,
             IInlineSuggestionsRequestCallback callback) {
-        synchronized (mMethodMap) {
+        synchronized (ImfLock.class) {
             onCreateInlineSuggestionsRequestLocked(userId, requestInfo, callback);
         }
     }
@@ -4777,12 +4854,12 @@
                 new ArrayMap<>();
         AdditionalSubtypeUtils.load(additionalSubtypeMap, userId);
         queryInputMethodServicesInternal(mContext, userId, additionalSubtypeMap,
-                methodMap, methodList);
+                methodMap, methodList, DirectBootAwareness.AUTO);
         return methodMap;
     }
 
     private boolean switchToInputMethod(String imeId, @UserIdInt int userId) {
-        synchronized (mMethodMap) {
+        synchronized (ImfLock.class) {
             if (userId == mSettings.getCurrentUserId()) {
                 if (!mMethodMap.containsKey(imeId)
                         || !mSettings.getEnabledInputMethodListLocked()
@@ -4808,7 +4885,7 @@
     }
 
     private boolean setInputMethodEnabled(String imeId, boolean enabled, @UserIdInt int userId) {
-        synchronized (mMethodMap) {
+        synchronized (ImfLock.class) {
             if (userId == mSettings.getCurrentUserId()) {
                 if (!mMethodMap.containsKey(imeId)) {
                     return false; // IME is not found.
@@ -4840,7 +4917,7 @@
             int displayId) {
         //TODO(b/150843766): Check if Input Token is valid.
         final IBinder curHostInputToken;
-        synchronized (mMethodMap) {
+        synchronized (ImfLock.class) {
             if (displayId != mCurTokenDisplayId || mCurHostInputToken == null) {
                 return false;
             }
@@ -4850,7 +4927,7 @@
     }
 
     private void reportImeControl(@Nullable IBinder windowToken, boolean imeParentChanged) {
-        synchronized (mMethodMap) {
+        synchronized (ImfLock.class) {
             if (mCurFocusedWindow != windowToken) {
                 // mCurPerceptible was set by the focused window, but it is no longer in control,
                 // so we reset mCurPerceptible.
@@ -4958,13 +5035,13 @@
             throw new InvalidParameterException("contentUri must have content scheme");
         }
 
-        synchronized (mMethodMap) {
+        synchronized (ImfLock.class) {
             final int uid = Binder.getCallingUid();
-            if (getSelectedMethodId() == null) {
+            if (getSelectedMethodIdLocked() == null) {
                 return null;
             }
-            if (getCurToken() != token) {
-                Slog.e(TAG, "Ignoring createInputContentUriToken mCurToken=" + getCurToken()
+            if (getCurTokenLocked() != token) {
+                Slog.e(TAG, "Ignoring createInputContentUriToken mCurToken=" + getCurTokenLocked()
                         + " token=" + token);
                 return null;
             }
@@ -4997,7 +5074,7 @@
 
     @BinderThread
     private void reportFullscreenMode(@NonNull IBinder token, boolean fullscreen) {
-        synchronized (mMethodMap) {
+        synchronized (ImfLock.class) {
             if (!calledWithValidTokenLocked(token)) {
                 return;
             }
@@ -5080,7 +5157,7 @@
 
         final Printer p = new PrintWriterPrinter(pw);
 
-        synchronized (mMethodMap) {
+        synchronized (ImfLock.class) {
             p.println("Current Input Method Manager state:");
             int N = mMethodList.size();
             p.println("  Input Methods: mMethodMapUpdateCount=" + mMethodMapUpdateCount);
@@ -5099,24 +5176,24 @@
                 p.println("    sessionRequested=" + ci.sessionRequested);
                 p.println("    curSession=" + ci.curSession);
             }
-            p.println("  mCurMethodId=" + getSelectedMethodId());
+            p.println("  mCurMethodId=" + getSelectedMethodIdLocked());
             client = mCurClient;
-            p.println("  mCurClient=" + client + " mCurSeq=" + getSequenceNumber());
+            p.println("  mCurClient=" + client + " mCurSeq=" + getSequenceNumberLocked());
             p.println("  mCurPerceptible=" + mCurPerceptible);
             p.println("  mCurFocusedWindow=" + mCurFocusedWindow
                     + " softInputMode=" +
                     InputMethodDebug.softInputModeToString(mCurFocusedWindowSoftInputMode)
                     + " client=" + mCurFocusedWindowClient);
             focusedWindowClient = mCurFocusedWindowClient;
-            p.println("  mCurId=" + getCurId() + " mHaveConnection=" + hasConnection()
+            p.println("  mCurId=" + getCurIdLocked() + " mHaveConnection=" + hasConnectionLocked()
                     + " mBoundToMethod=" + mBoundToMethod + " mVisibleBound="
                     + mBindingController.isVisibleBound());
-            p.println("  mCurToken=" + getCurToken());
+            p.println("  mCurToken=" + getCurTokenLocked());
             p.println("  mCurTokenDisplayId=" + mCurTokenDisplayId);
             p.println("  mCurHostInputToken=" + mCurHostInputToken);
-            p.println("  mCurIntent=" + getCurIntent());
-            method = getCurMethod();
-            p.println("  mCurMethod=" + getCurMethod());
+            p.println("  mCurIntent=" + getCurIntentLocked());
+            method = getCurMethodLocked();
+            p.println("  mCurMethod=" + getCurMethodLocked());
             p.println("  mEnabledSession=" + mEnabledSession);
             p.println("  mShowRequested=" + mShowRequested
                     + " mShowExplicitlyRequested=" + mShowExplicitlyRequested
@@ -5365,7 +5442,7 @@
     @BinderThread
     @ShellCommandResult
     private int getLastSwitchUserId(@NonNull ShellCommand shellCommand) {
-        synchronized (mMethodMap) {
+        synchronized (ImfLock.class) {
             shellCommand.getOutPrintWriter().println(mLastSwitchUserId);
             return ShellCommandResult.SUCCESS;
         }
@@ -5400,13 +5477,13 @@
                     break;
             }
         }
-        synchronized (mMethodMap) {
+        synchronized (ImfLock.class) {
             final PrintWriter pr = shellCommand.getOutPrintWriter();
             final int[] userIds = InputMethodUtils.resolveUserId(userIdToBeResolved,
                     mSettings.getCurrentUserId(), shellCommand.getErrPrintWriter());
             for (int userId : userIds) {
                 final List<InputMethodInfo> methods = all
-                        ? getInputMethodListLocked(userId)
+                        ? getInputMethodListLocked(userId, DirectBootAwareness.AUTO)
                         : getEnabledInputMethodListLocked(userId);
                 if (userIds.length > 1) {
                     pr.print("User #");
@@ -5442,7 +5519,7 @@
         final PrintWriter out = shellCommand.getOutPrintWriter();
         final PrintWriter error = shellCommand.getErrPrintWriter();
         boolean hasFailed = false;
-        synchronized (mMethodMap) {
+        synchronized (ImfLock.class) {
             final int[] userIds = InputMethodUtils.resolveUserId(userIdToBeResolved,
                     mSettings.getCurrentUserId(), shellCommand.getErrPrintWriter());
             for (int userId : userIds) {
@@ -5496,7 +5573,7 @@
      * @return {@code false} if it fails to enable the IME.  {@code false} otherwise.
      */
     @BinderThread
-    @GuardedBy("mMethodMap")
+    @GuardedBy("ImfLock.class")
     private boolean handleShellCommandEnableDisableInputMethodInternalLocked(
             @UserIdInt int userId, String imeId, boolean enabled, PrintWriter out,
             PrintWriter error) {
@@ -5566,7 +5643,7 @@
         final PrintWriter out = shellCommand.getOutPrintWriter();
         final PrintWriter error = shellCommand.getErrPrintWriter();
         boolean hasFailed = false;
-        synchronized (mMethodMap) {
+        synchronized (ImfLock.class) {
             final int[] userIds = InputMethodUtils.resolveUserId(userIdToBeResolved,
                     mSettings.getCurrentUserId(), shellCommand.getErrPrintWriter());
             for (int userId : userIds) {
@@ -5604,7 +5681,7 @@
     private int handleShellCommandResetInputMethod(@NonNull ShellCommand shellCommand) {
         final PrintWriter out = shellCommand.getOutPrintWriter();
         final int userIdToBeResolved = handleOptionsForCommandsThatOnlyHaveUserOption(shellCommand);
-        synchronized (mMethodMap) {
+        synchronized (ImfLock.class) {
             final int[] userIds = InputMethodUtils.resolveUserId(userIdToBeResolved,
                     mSettings.getCurrentUserId(), shellCommand.getErrPrintWriter());
             for (int userId : userIds) {
@@ -5616,17 +5693,21 @@
                 if (userId == mSettings.getCurrentUserId()) {
                     hideCurrentInputLocked(mCurFocusedWindow, 0, null,
                             SoftInputShowHideReason.HIDE_RESET_SHELL_COMMAND);
-                    mBindingController.unbindCurrentMethodLocked();
+                    mBindingController.unbindCurrentMethod();
                     // Reset the current IME
                     resetSelectedInputMethodAndSubtypeLocked(null);
                     // Also reset the settings of the current IME
                     mSettings.putSelectedInputMethod(null);
                     // Disable all enabled IMEs.
-                    mSettings.getEnabledInputMethodListLocked().forEach(
-                            imi -> setInputMethodEnabledLocked(imi.getId(), false));
+                    for (InputMethodInfo inputMethodInfo :
+                            mSettings.getEnabledInputMethodListLocked()) {
+                        setInputMethodEnabledLocked(inputMethodInfo.getId(), false);
+                    }
                     // Re-enable with default enabled IMEs.
-                    InputMethodUtils.getDefaultEnabledImes(mContext, mMethodList).forEach(
-                            imi -> setInputMethodEnabledLocked(imi.getId(), true));
+                    for (InputMethodInfo imi :
+                            InputMethodUtils.getDefaultEnabledImes(mContext, mMethodList)) {
+                        setInputMethodEnabledLocked(imi.getId(), true);
+                    }
                     updateInputMethodsFromSettingsLocked(true /* enabledMayChange */);
                     InputMethodUtils.setNonSelectedSystemImesDisabledUntilUsed(mIPackageManager,
                             mSettings.getEnabledInputMethodListLocked(),
@@ -5641,7 +5722,7 @@
                             new ArrayMap<>();
                     AdditionalSubtypeUtils.load(additionalSubtypeMap, userId);
                     queryInputMethodServicesInternal(mContext, userId, additionalSubtypeMap,
-                            methodMap, methodList);
+                            methodMap, methodList, DirectBootAwareness.AUTO);
                     final InputMethodSettings settings = new InputMethodSettings(
                             mContext.getResources(), mContext.getContentResolver(), methodMap,
                             userId, false);
@@ -5678,7 +5759,7 @@
         final PrintWriter pw = shellCommand.getOutPrintWriter();
         switch (cmd) {
             case "start":
-                ImeTracing.getInstance().getInstance().startTrace(pw);
+                ImeTracing.getInstance().startTrace(pw);
                 break;  // proceed to the next step to update the IME client processes.
             case "stop":
                 ImeTracing.getInstance().stopTrace(pw);
@@ -5695,7 +5776,7 @@
         }
         boolean isImeTraceEnabled = ImeTracing.getInstance().isEnabled();
         ArrayMap<IBinder, ClientState> clients;
-        synchronized (mMethodMap) {
+        synchronized (ImfLock.class) {
             clients = new ArrayMap<>(mClients);
         }
         for (ClientState state : clients.values()) {
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java b/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java
index f70ad05..132be7d 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java
@@ -46,6 +46,7 @@
 import android.widget.Switch;
 import android.widget.TextView;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.LocalServices;
 import com.android.server.inputmethod.InputMethodSubtypeSwitchingController.ImeSubtypeListItem;
@@ -98,7 +99,7 @@
         int lastInputMethodSubtypeId = mSettings.getSelectedInputMethodSubtypeId(lastInputMethodId);
         if (DEBUG) Slog.v(TAG, "Current IME: " + lastInputMethodId);
 
-        synchronized (mMethodMap) {
+        synchronized (ImfLock.class) {
             final List<ImeSubtypeListItem> imList = mSwitchingController
                     .getSortedInputMethodAndSubtypeListForImeMenuLocked(
                             showAuxSubtypes, isScreenLocked);
@@ -112,7 +113,7 @@
                 final InputMethodSubtype currentSubtype =
                         mService.getCurrentInputMethodSubtypeLocked();
                 if (currentSubtype != null) {
-                    final String curMethodId = mService.getCurrentMethodId();
+                    final String curMethodId = mService.getSelectedMethodIdLocked();
                     final InputMethodInfo currentImi = mMethodMap.get(curMethodId);
                     lastInputMethodSubtypeId = InputMethodUtils.getSubtypeIdFromHashCode(
                             currentImi, currentSubtype.hashCode());
@@ -175,7 +176,7 @@
             final ImeSubtypeListAdapter adapter = new ImeSubtypeListAdapter(dialogContext,
                     com.android.internal.R.layout.input_method_switch_item, imList, checkedItem);
             final DialogInterface.OnClickListener choiceListener = (dialog, which) -> {
-                synchronized (mMethodMap) {
+                synchronized (ImfLock.class) {
                     if (mIms == null || mIms.length <= which || mSubtypeIds == null
                             || mSubtypeIds.length <= which) {
                         return;
@@ -250,11 +251,12 @@
     }
 
     void hideInputMethodMenu() {
-        synchronized (mMethodMap) {
+        synchronized (ImfLock.class) {
             hideInputMethodMenuLocked();
         }
     }
 
+    @GuardedBy("ImfLock.class")
     void hideInputMethodMenuLocked() {
         if (DEBUG) Slog.v(TAG, "Hide switching menu");
 
@@ -299,7 +301,7 @@
             if (DEBUG) {
                 Slog.w(TAG, "HardKeyboardStatusChanged: available=" + available);
             }
-            synchronized (mMethodMap) {
+            synchronized (ImfLock.class) {
                 if (mSwitchingDialog != null && mSwitchingDialogTitleView != null
                         && mSwitchingDialog.isShowing()) {
                     mSwitchingDialogTitleView.findViewById(
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodSubtypeSwitchingController.java b/services/core/java/com/android/server/inputmethod/InputMethodSubtypeSwitchingController.java
index c340a2b..f8894c6 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodSubtypeSwitchingController.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodSubtypeSwitchingController.java
@@ -39,7 +39,7 @@
  * InputMethodSubtypeSwitchingController controls the switching behavior of the subtypes.
  *
  * <p>This class is designed to be used from and only from {@link InputMethodManagerService} by
- * using {@link InputMethodManagerService#mMethodMap} as a global lock.</p>
+ * using {@link ImfLock ImfLock.class} as a global lock.</p>
  */
 final class InputMethodSubtypeSwitchingController {
     private static final String TAG = InputMethodSubtypeSwitchingController.class.getSimpleName();
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 0fd7cc1..e40d86a 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubClientBroker.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubClientBroker.java
@@ -331,15 +331,7 @@
         mAppOpsManager = context.getSystemService(AppOpsManager.class);
 
         startMonitoringOpChanges();
-
-        HostEndpointInfo info = new HostEndpointInfo();
-        info.hostEndpointId = (char) mHostEndPointId;
-        info.packageName = mPackage;
-        info.attributionTag = mAttributionTag;
-        info.type = (mUid == Process.SYSTEM_UID)
-             ? HostEndpointInfo.Type.TYPE_FRAMEWORK
-             : HostEndpointInfo.Type.TYPE_APP;
-        mContextHubProxy.onHostEndpointConnected(info);
+        sendHostEndpointConnectedEvent();
     }
 
     /* package */ ContextHubClientBroker(
@@ -556,6 +548,9 @@
     /* package */ void onHubReset() {
         invokeCallback(callback -> callback.onHubReset());
         sendPendingIntent(() -> createIntent(ContextHubManager.EVENT_HUB_RESET));
+
+        // Re-send the host endpoint connected event as the Context Hub restarted.
+        sendHostEndpointConnectedEvent();
     }
 
     /**
@@ -895,6 +890,17 @@
         }
     }
 
+    private void sendHostEndpointConnectedEvent() {
+        HostEndpointInfo info = new HostEndpointInfo();
+        info.hostEndpointId = (char) mHostEndPointId;
+        info.packageName = mPackage;
+        info.attributionTag = mAttributionTag;
+        info.type = (mUid == Process.SYSTEM_UID)
+             ? HostEndpointInfo.Type.TYPE_FRAMEWORK
+             : HostEndpointInfo.Type.TYPE_APP;
+        mContextHubProxy.onHostEndpointConnected(info);
+    }
+
     /**
      * Dump debugging info as ClientBrokerProto
      *
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 fc9697d..61e6d14 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubService.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubService.java
@@ -72,6 +72,9 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicLong;
 
@@ -138,11 +141,23 @@
     // The manager for the internal nanoapp state cache
     private final NanoAppStateManager mNanoAppStateManager = new NanoAppStateManager();
 
+    // An executor and the future object for scheduling timeout timers
+    private final ScheduledThreadPoolExecutor mDailyMetricTimer =
+            new ScheduledThreadPoolExecutor(1);
+
+
+    // The period of the recurring time
+    private static final int PERIOD_METRIC_QUERY_DAYS = 1;
+
     // True if WiFi is available for the Context Hub
     private boolean mIsWifiAvailable = false;
     private boolean mIsWifiScanningEnabled = false;
     private boolean mIsWifiMainEnabled = false;
 
+    // A hashmap used to record if a contexthub is waiting for daily query
+    private Set<Integer> mMetricQueryPendingContextHubIds =
+            Collections.newSetFromMap(new ConcurrentHashMap<Integer, Boolean>());
+
     // Lock object for sendWifiSettingUpdate()
     private final Object mSendWifiSettingUpdateLock = new Object();
 
@@ -317,6 +332,8 @@
                     });
 
         }
+
+        scheduleDailyMetricSnapshot();
     }
 
     /**
@@ -747,6 +764,18 @@
      * @param nanoappStateList the list of loaded nanoapps
      */
     private void handleQueryAppsCallback(int contextHubId, List<NanoAppState> nanoappStateList) {
+        if (mMetricQueryPendingContextHubIds.contains(contextHubId)) {
+            for (NanoAppState nanoappState : nanoappStateList) {
+                ContextHubStatsLog.write(
+                        ContextHubStatsLog.CONTEXT_HUB_LOADED_NANOAPP_SNAPSHOT_REPORTED,
+                        contextHubId, nanoappState.getNanoAppId(),
+                        (int) nanoappState.getNanoAppVersion());
+            }
+            mMetricQueryPendingContextHubIds.remove(contextHubId);
+            if (mMetricQueryPendingContextHubIds.isEmpty()) {
+                scheduleDailyMetricSnapshot();
+            }
+        }
         mNanoAppStateManager.updateCache(contextHubId, nanoappStateList);
         mTransactionManager.onQueryResponse(nanoappStateList);
     }
@@ -1135,6 +1164,23 @@
         sendMicrophoneDisableSettingUpdate(isEnabled);
     }
 
+    /**
+     *  Invokes a daily timer to query all context hubs
+     */
+    private void scheduleDailyMetricSnapshot() {
+        Runnable queryAllContextHub = () -> {
+            for (int contextHubId : mContextHubIdToInfoMap.keySet()) {
+                mMetricQueryPendingContextHubIds.add(contextHubId);
+                queryNanoAppsInternal(contextHubId);
+            }
+        };
+        try {
+            mDailyMetricTimer.schedule(queryAllContextHub, PERIOD_METRIC_QUERY_DAYS,
+                    TimeUnit.DAYS);
+        } catch (Exception e) {
+            Log.e(TAG, "Error when schedule a timer", e);
+        }
+    }
 
     private String getCallingPackageName() {
         return mContext.getPackageManager().getNameForUid(Binder.getCallingUid());
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 abf5a24..c199bb3 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubTransactionManager.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubTransactionManager.java
@@ -152,6 +152,14 @@
 
             @Override
                 /* package */ void onTransactionComplete(@ContextHubTransaction.Result int result) {
+                ContextHubStatsLog.write(
+                        ContextHubStatsLog.CHRE_CODE_DOWNLOAD_TRANSACTED,
+                        nanoAppBinary.getNanoAppId(),
+                        nanoAppBinary.getNanoAppVersion(),
+                        ContextHubStatsLog
+                            .CHRE_CODE_DOWNLOAD_TRANSACTED__TRANSACTION_TYPE__TYPE_LOAD,
+                        toStatsTransactionResult(result));
+
                 if (result == ContextHubTransaction.RESULT_SUCCESS) {
                     // NOTE: The legacy JNI code used to do a query right after a load success
                     // to synchronize the service cache. Instead store the binary that was
@@ -200,6 +208,13 @@
 
             @Override
                 /* package */ void onTransactionComplete(@ContextHubTransaction.Result int result) {
+                ContextHubStatsLog.write(
+                        ContextHubStatsLog.CHRE_CODE_DOWNLOAD_TRANSACTED, nanoAppId,
+                        0 /* nanoappVersion */,
+                        ContextHubStatsLog
+                            .CHRE_CODE_DOWNLOAD_TRANSACTED__TRANSACTION_TYPE__TYPE_UNLOAD,
+                        toStatsTransactionResult(result));
+
                 if (result == ContextHubTransaction.RESULT_SUCCESS) {
                     mNanoAppStateManager.removeNanoAppInstance(contextHubId, nanoAppId);
                 }
@@ -463,8 +478,12 @@
                 };
 
                 long timeoutSeconds = transaction.getTimeout(TimeUnit.SECONDS);
-                mTimeoutFuture = mTimeoutExecutor.schedule(onTimeoutFunc, timeoutSeconds,
+                try {
+                    mTimeoutFuture = mTimeoutExecutor.schedule(onTimeoutFunc, timeoutSeconds,
                         TimeUnit.SECONDS);
+                } catch (Exception e) {
+                    Log.e(TAG, "Error when schedule a timer", e);
+                }
             } else {
                 transaction.onTransactionComplete(
                         ContextHubServiceUtil.toTransactionResult(result));
@@ -473,6 +492,30 @@
         }
     }
 
+    private int toStatsTransactionResult(@ContextHubTransaction.Result int result) {
+        switch (result) {
+            case ContextHubTransaction.RESULT_SUCCESS:
+                return ContextHubStatsLog.CHRE_CODE_DOWNLOAD_TRANSACTED__TRANSACTION_RESULT__TRANSACTION_RESULT_SUCCESS;
+            case ContextHubTransaction.RESULT_FAILED_BAD_PARAMS:
+                return ContextHubStatsLog.CHRE_CODE_DOWNLOAD_TRANSACTED__TRANSACTION_RESULT__TRANSACTION_RESULT_FAILED_BAD_PARAMS;
+            case ContextHubTransaction.RESULT_FAILED_UNINITIALIZED:
+                return ContextHubStatsLog.CHRE_CODE_DOWNLOAD_TRANSACTED__TRANSACTION_RESULT__TRANSACTION_RESULT_FAILED_UNINITIALIZED;
+            case ContextHubTransaction.RESULT_FAILED_BUSY:
+                return ContextHubStatsLog.CHRE_CODE_DOWNLOAD_TRANSACTED__TRANSACTION_RESULT__TRANSACTION_RESULT_FAILED_BUSY;
+            case ContextHubTransaction.RESULT_FAILED_AT_HUB:
+                return ContextHubStatsLog.CHRE_CODE_DOWNLOAD_TRANSACTED__TRANSACTION_RESULT__TRANSACTION_RESULT_FAILED_AT_HUB;
+            case ContextHubTransaction.RESULT_FAILED_TIMEOUT:
+                return ContextHubStatsLog.CHRE_CODE_DOWNLOAD_TRANSACTED__TRANSACTION_RESULT__TRANSACTION_RESULT_FAILED_TIMEOUT;
+            case ContextHubTransaction.RESULT_FAILED_SERVICE_INTERNAL_FAILURE:
+                return ContextHubStatsLog.CHRE_CODE_DOWNLOAD_TRANSACTED__TRANSACTION_RESULT__TRANSACTION_RESULT_FAILED_SERVICE_INTERNAL_FAILURE;
+            case ContextHubTransaction.RESULT_FAILED_HAL_UNAVAILABLE:
+                return ContextHubStatsLog.CHRE_CODE_DOWNLOAD_TRANSACTED__TRANSACTION_RESULT__TRANSACTION_RESULT_FAILED_HAL_UNAVAILABLE;
+            case ContextHubTransaction.RESULT_FAILED_UNKNOWN:
+            default: /* fall through */
+                return ContextHubStatsLog.CHRE_CODE_DOWNLOAD_TRANSACTED__TRANSACTION_RESULT__TRANSACTION_RESULT_FAILED_UNKNOWN;
+        }
+    }
+
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder(100);
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 9078f3f..cc5aaf4 100644
--- a/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
+++ b/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
@@ -41,8 +41,10 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.NoSuchElementException;
 import java.util.Set;
 
@@ -320,9 +322,8 @@
     private static class ContextHubWrapperAidl extends IContextHubWrapper {
         private android.hardware.contexthub.IContextHub mHub;
 
-        private ICallback mCallback = null;
-
-        private ContextHubAidlCallback mAidlCallback = new ContextHubAidlCallback();
+        private final Map<Integer, ContextHubAidlCallback> mAidlCallbackMap =
+                    new HashMap<>();
 
         // Use this thread in case where the execution requires to be on a service thread.
         // For instance, AppOpsManager.noteOp requires the UPDATE_APP_OPS_STATS permission.
@@ -332,6 +333,14 @@
 
         private class ContextHubAidlCallback extends
                 android.hardware.contexthub.IContextHubCallback.Stub {
+            private final int mContextHubId;
+            private final ICallback mCallback;
+
+            ContextHubAidlCallback(int contextHubId, ICallback callback) {
+                mContextHubId = contextHubId;
+                mCallback = callback;
+            }
+
             public void handleNanoappInfo(android.hardware.contexthub.NanoappInfo[] appInfo) {
                 List<NanoAppState> nanoAppStateList =
                         ContextHubServiceUtil.createNanoAppStateList(appInfo);
@@ -481,8 +490,8 @@
         }
 
         public void registerCallback(int contextHubId, ICallback callback) throws RemoteException {
-            mCallback = callback;
-            mHub.registerCallback(contextHubId, mAidlCallback);
+            mAidlCallbackMap.put(contextHubId, new ContextHubAidlCallback(contextHubId, callback));
+            mHub.registerCallback(contextHubId, mAidlCallbackMap.get(contextHubId));
         }
 
         @ContextHubTransaction.Result
@@ -508,10 +517,18 @@
 
         protected ICallback mCallback = null;
 
-        protected final ContextHubWrapperHidlCallback mHidlCallback =
-                new ContextHubWrapperHidlCallback();
+        protected final Map<Integer, ContextHubWrapperHidlCallback> mHidlCallbackMap =
+                    new HashMap<>();
 
         protected class ContextHubWrapperHidlCallback extends IContexthubCallback.Stub {
+            private final int mContextHubId;
+            private final ICallback mCallback;
+
+            ContextHubWrapperHidlCallback(int contextHubId, ICallback callback) {
+                mContextHubId = contextHubId;
+                mCallback = callback;
+            }
+
             @Override
             public void handleClientMsg(ContextHubMsg message) {
                 mCallback.handleNanoappMessage(
@@ -612,8 +629,9 @@
         }
 
         public void registerCallback(int contextHubId, ICallback callback) throws RemoteException {
-            mCallback = callback;
-            mHub.registerCallback(contextHubId, mHidlCallback);
+            mHidlCallbackMap.put(contextHubId,
+                        new ContextHubWrapperHidlCallback(contextHubId, callback));
+            mHub.registerCallback(contextHubId, mHidlCallbackMap.get(contextHubId));
         }
 
         public void onWifiMainSettingChanged(boolean enabled) {}
@@ -779,8 +797,9 @@
         }
 
         public void registerCallback(int contextHubId, ICallback callback) throws RemoteException {
-            mCallback = callback;
-            mHub.registerCallback_1_2(contextHubId, mHidlCallback);
+            mHidlCallbackMap.put(contextHubId,
+                        new ContextHubWrapperHidlCallback(contextHubId, callback));
+            mHub.registerCallback_1_2(contextHubId, mHidlCallbackMap.get(contextHubId));
         }
 
         private void sendSettingChanged(byte setting, byte newValue) {
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 47146c1..d08e5dc 100644
--- a/services/core/java/com/android/server/location/eventlog/LocalEventLog.java
+++ b/services/core/java/com/android/server/location/eventlog/LocalEventLog.java
@@ -21,26 +21,23 @@
 import android.annotation.Nullable;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.Preconditions;
 
 import java.lang.reflect.Array;
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.ConcurrentModificationException;
 import java.util.NoSuchElementException;
 import java.util.Objects;
 
 /**
  * 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 class LocalEventLog<T> {
 
-    /**
-     * Consumer of log events for iterating over the log.
-     *
-     * @param <T> log event type
-     */
+    /** Consumer of log events for iterating over the log. */
     public interface LogConsumer<T> {
         /** Invoked with a time and a logEvent. */
         void acceptLog(long time, T logEvent);
@@ -48,12 +45,13 @@
 
     // 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 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);
 
+    @VisibleForTesting
     static final int MAX_TIME_DELTA = (1 << bitCount(TIME_DELTA_MASK)) - 1;
 
     private static int countTrailingZeros(int i) {
@@ -79,7 +77,7 @@
         return (entry & IS_FILLER_MASK) != 0;
     }
 
-    // circular buffer of log entries and events. each entry corrosponds to the log event at the
+    // circular buffer of log entries and events. each entry corresponds 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.
 
@@ -103,6 +101,9 @@
     @GuardedBy("this")
     long mLastLogTime;
 
+    @GuardedBy("this")
+    long mModificationCount;
+
     @SuppressWarnings("unchecked")
     public LocalEventLog(int size, Class<T> clazz) {
         Preconditions.checkArgument(size > 0);
@@ -143,6 +144,7 @@
         if (isEmpty()) {
             mStartTime = time;
             mLastLogTime = mStartTime;
+            mModificationCount++;
         }
 
         addLogEventInternal(false, (int) delta, logEvent);
@@ -156,6 +158,7 @@
         if (mLogSize == mEntries.length) {
             // if log is full, size will remain the same, but update the start time
             mStartTime += getTimeDelta(mEntries[startIndex()]);
+            mModificationCount++;
         } else {
             // otherwise add an item
             mLogSize++;
@@ -170,11 +173,12 @@
 
     /** Clears the log of all entries. */
     public synchronized void clear() {
-        // clear entries to allow gc
+        // clear entries to aid gc
         Arrays.fill(mLogEvents, null);
 
         mLogEndIndex = 0;
         mLogSize = 0;
+        mModificationCount++;
 
         mStartTime = -1;
         mLastLogTime = -1;
@@ -186,7 +190,10 @@
         return mLogSize == 0;
     }
 
-    /** Iterates over the event log, passing each log string to the given consumer. */
+    /**
+     * Iterates over the event log, passing each log event to the given consumer. Locks the log
+     * while executing so that {@link ConcurrentModificationException}s cannot occur.
+     */
     public synchronized void iterate(LogConsumer<? super T> consumer) {
         LogIterator it = new LogIterator();
         while (it.hasNext()) {
@@ -195,15 +202,53 @@
         }
     }
 
+    /**
+     * Iterates over all the given event logs in time order, passing each log event to the given
+     * consumer. It is the caller's responsibility to ensure that {@link
+     * ConcurrentModificationException}s cannot occur, whether through locking or other means.
+     */
+    @SafeVarargs
+    public static <T> void iterate(LogConsumer<? super T> consumer, LocalEventLog<T>... logs) {
+        ArrayList<LocalEventLog<T>.LogIterator> its = new ArrayList<>(logs.length);
+        for (LocalEventLog<T> log : logs) {
+            LocalEventLog<T>.LogIterator it = log.new LogIterator();
+            if (it.hasNext()) {
+                its.add(it);
+                it.next();
+            }
+        }
+
+        while (true) {
+            LocalEventLog<T>.LogIterator next = null;
+            for (LocalEventLog<T>.LogIterator it : its) {
+                if (it != null && (next == null || it.getTime() < next.getTime())) {
+                    next = it;
+                }
+            }
+
+            if (next == null) {
+                return;
+            }
+
+            consumer.acceptLog(next.getTime(), next.getLog());
+
+            if (next.hasNext()) {
+                next.next();
+            } else {
+                its.remove(next);
+            }
+        }
+    }
+
     // returns the index of the first element
     @GuardedBy("this")
-    private int startIndex() {
+    int startIndex() {
         return wrapIndex(mLogEndIndex - mLogSize);
     }
 
     // returns the index after this one
     @GuardedBy("this")
-    private int incrementIndex(int index) {
+    int incrementIndex(int index) {
         if (index == -1) {
             return startIndex();
         } else if (index >= 0) {
@@ -215,12 +260,15 @@
 
     // rolls over the given index if necessary
     @GuardedBy("this")
-    private int wrapIndex(int index) {
+    int wrapIndex(int index) {
         // java modulo will keep negative sign, we need to rollover
         return (index % mEntries.length + mEntries.length) % mEntries.length;
     }
 
-    private class LogIterator {
+    /** Iterator over log times and events. */
+    protected final class LogIterator {
+
+        private final long mModificationCount;
 
         private long mLogTime;
         private int mIndex;
@@ -229,8 +277,10 @@
         private long mCurrentTime;
         private T mCurrentLogEvent;
 
-        LogIterator() {
+        public LogIterator() {
             synchronized (LocalEventLog.this) {
+                mModificationCount = LocalEventLog.this.mModificationCount;
+
                 mLogTime = mStartTime;
                 mIndex = -1;
                 mCount = -1;
@@ -241,6 +291,7 @@
 
         public boolean hasNext() {
             synchronized (LocalEventLog.this) {
+                checkModifications();
                 return mCount < mLogSize;
             }
         }
@@ -277,5 +328,12 @@
                 }
             } while (mCount < mLogSize && isFiller(mEntries[mIndex]));
         }
+
+        @GuardedBy("LocalEventLog.this")
+        private void checkModifications() {
+            if (mModificationCount != LocalEventLog.this.mModificationCount) {
+                throw new ConcurrentModificationException();
+            }
+        }
     }
 }
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 94953e0..45436e7 100644
--- a/services/core/java/com/android/server/location/eventlog/LocationEventLog.java
+++ b/services/core/java/com/android/server/location/eventlog/LocationEventLog.java
@@ -52,16 +52,28 @@
         if (D) {
             return 600;
         } else {
+            return 300;
+        }
+    }
+
+    private static int getLocationsLogSize() {
+        if (D) {
             return 200;
+        } else {
+            return 100;
         }
     }
 
     @GuardedBy("mAggregateStats")
     private final ArrayMap<String, ArrayMap<CallerIdentity, AggregateStats>> mAggregateStats;
 
-    public LocationEventLog() {
+    @GuardedBy("this")
+    private final LocationsEventLog mLocationsLog;
+
+    private LocationEventLog() {
         super(getLogSize(), Object.class);
         mAggregateStats = new ArrayMap<>(4);
+        mLocationsLog = new LocationsEventLog(getLocationsLogSize());
     }
 
     /** Copies out all aggregated stats. */
@@ -95,39 +107,39 @@
 
     /** Logs a user switched event. */
     public void logUserSwitched(int userIdFrom, int userIdTo) {
-        addLogEvent(new UserSwitchedEvent(userIdFrom, userIdTo));
+        addLog(new UserSwitchedEvent(userIdFrom, userIdTo));
     }
 
     /** Logs a location enabled/disabled event. */
     public void logLocationEnabled(int userId, boolean enabled) {
-        addLogEvent(new LocationEnabledEvent(userId, enabled));
+        addLog(new LocationEnabledEvent(userId, enabled));
     }
 
     /** Logs a location enabled/disabled event. */
     public void logAdasLocationEnabled(int userId, boolean enabled) {
-        addLogEvent(new LocationAdasEnabledEvent(userId, enabled));
+        addLog(new LocationAdasEnabledEvent(userId, enabled));
     }
 
     /** Logs a location provider enabled/disabled event. */
     public void logProviderEnabled(String provider, int userId, boolean enabled) {
-        addLogEvent(new ProviderEnabledEvent(provider, userId, enabled));
+        addLog(new ProviderEnabledEvent(provider, userId, enabled));
     }
 
     /** Logs a location provider being replaced/unreplaced by a mock provider. */
     public void logProviderMocked(String provider, boolean mocked) {
-        addLogEvent(new ProviderMockedEvent(provider, mocked));
+        addLog(new ProviderMockedEvent(provider, mocked));
     }
 
     /** Logs a new client registration for a location provider. */
     public void logProviderClientRegistered(String provider, CallerIdentity identity,
             LocationRequest request) {
-        addLogEvent(new ProviderClientRegisterEvent(provider, true, identity, request));
+        addLog(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(new ProviderClientRegisterEvent(provider, false, identity, null));
+        addLog(new ProviderClientRegisterEvent(provider, false, identity, null));
         getAggregateStats(provider, identity).markRequestRemoved();
     }
 
@@ -144,7 +156,7 @@
     /** Logs a client for a location provider entering the foreground state. */
     public void logProviderClientForeground(String provider, CallerIdentity identity) {
         if (D) {
-            addLogEvent(new ProviderClientForegroundEvent(provider, true, identity));
+            addLog(new ProviderClientForegroundEvent(provider, true, identity));
         }
         getAggregateStats(provider, identity).markRequestForeground();
     }
@@ -152,7 +164,7 @@
     /** Logs a client for a location provider leaving the foreground state. */
     public void logProviderClientBackground(String provider, CallerIdentity identity) {
         if (D) {
-            addLogEvent(new ProviderClientForegroundEvent(provider, false, identity));
+            addLog(new ProviderClientForegroundEvent(provider, false, identity));
         }
         getAggregateStats(provider, identity).markRequestBackground();
     }
@@ -160,32 +172,34 @@
     /** Logs a client for a location provider entering the permitted state. */
     public void logProviderClientPermitted(String provider, CallerIdentity identity) {
         if (D) {
-            addLogEvent(new ProviderClientPermittedEvent(provider, true, identity));
+            addLog(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(new ProviderClientPermittedEvent(provider, false, identity));
+            addLog(new ProviderClientPermittedEvent(provider, false, identity));
         }
     }
 
     /** Logs a change to the provider request for a location provider. */
     public void logProviderUpdateRequest(String provider, ProviderRequest request) {
-        addLogEvent(new ProviderUpdateEvent(provider, request));
+        addLog(new ProviderUpdateEvent(provider, request));
     }
 
     /** Logs a new incoming location for a location provider. */
     public void logProviderReceivedLocations(String provider, int numLocations) {
-        addLogEvent(new ProviderReceiveLocationEvent(provider, numLocations));
+        synchronized (this) {
+            mLocationsLog.logProviderReceivedLocations(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(new ProviderDeliverLocationEvent(provider, numLocations, identity));
+        synchronized (this) {
+            mLocationsLog.logProviderDeliveredLocations(provider, numLocations, identity);
         }
         getAggregateStats(provider, identity).markLocationDelivered();
     }
@@ -193,19 +207,24 @@
     /** Logs that a provider has entered or exited stationary throttling. */
     public void logProviderStationaryThrottled(String provider, boolean throttled,
             ProviderRequest request) {
-        addLogEvent(new ProviderStationaryThrottledEvent(provider, throttled, request));
+        addLog(new ProviderStationaryThrottledEvent(provider, throttled, request));
     }
 
     /** Logs that the location power save mode has changed. */
     public void logLocationPowerSaveMode(
             @LocationPowerSaveMode int locationPowerSaveMode) {
-        addLogEvent(new LocationPowerSaveModeEvent(locationPowerSaveMode));
+        addLog(new LocationPowerSaveModeEvent(locationPowerSaveMode));
     }
 
-    private void addLogEvent(Object logEvent) {
+    private void addLog(Object logEvent) {
         addLog(SystemClock.elapsedRealtime(), logEvent);
     }
 
+    @Override
+    public synchronized void iterate(LogConsumer<? super Object> consumer) {
+        iterate(consumer, this, mLocationsLog);
+    }
+
     public void iterate(Consumer<String> consumer) {
         iterate(consumer, null);
     }
@@ -488,6 +507,26 @@
         }
     }
 
+    private static final class LocationsEventLog extends LocalEventLog<Object> {
+
+        LocationsEventLog(int size) {
+            super(size, Object.class);
+        }
+
+        public void logProviderReceivedLocations(String provider, int numLocations) {
+            addLog(new ProviderReceiveLocationEvent(provider, numLocations));
+        }
+
+        public void logProviderDeliveredLocations(String provider, int numLocations,
+                CallerIdentity identity) {
+            addLog(new ProviderDeliverLocationEvent(provider, numLocations, identity));
+        }
+
+        private void addLog(Object logEvent) {
+            this.addLog(SystemClock.elapsedRealtime(), logEvent);
+        }
+    }
+
     /**
      * Aggregate statistics for a single package under a single provider.
      */
diff --git a/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java b/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java
index 699f143..7bb0d48 100644
--- a/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java
@@ -114,7 +114,8 @@
     protected boolean registerWithService(GnssMeasurementRequest request,
             Collection<GnssListenerRegistration> registrations) {
         if (mGnssNative.startMeasurementCollection(request.isFullTracking(),
-                request.isCorrelationVectorOutputsEnabled())) {
+                request.isCorrelationVectorOutputsEnabled(),
+                request.getIntervalMillis())) {
             if (D) {
                 Log.d(TAG, "starting gnss measurements (" + request + ")");
             }
diff --git a/services/core/java/com/android/server/location/gnss/hal/GnssNative.java b/services/core/java/com/android/server/location/gnss/hal/GnssNative.java
index 1eef0de..a513e08 100644
--- a/services/core/java/com/android/server/location/gnss/hal/GnssNative.java
+++ b/services/core/java/com/android/server/location/gnss/hal/GnssNative.java
@@ -623,8 +623,38 @@
     public void injectLocation(Location location) {
         Preconditions.checkState(mRegistered);
         if (location.hasAccuracy()) {
-            mGnssHal.injectLocation(location.getLatitude(), location.getLongitude(),
-                    location.getAccuracy());
+
+            int gnssLocationFlags = GNSS_LOCATION_HAS_LAT_LONG
+                    | (location.hasAltitude() ? GNSS_LOCATION_HAS_ALTITUDE : 0)
+                    | (location.hasSpeed() ? GNSS_LOCATION_HAS_SPEED : 0)
+                    | (location.hasBearing() ? GNSS_LOCATION_HAS_BEARING : 0)
+                    | (location.hasAccuracy() ? GNSS_LOCATION_HAS_HORIZONTAL_ACCURACY : 0)
+                    | (location.hasVerticalAccuracy() ? GNSS_LOCATION_HAS_VERTICAL_ACCURACY : 0)
+                    | (location.hasSpeedAccuracy() ? GNSS_LOCATION_HAS_SPEED_ACCURACY : 0)
+                    | (location.hasBearingAccuracy() ? GNSS_LOCATION_HAS_BEARING_ACCURACY : 0);
+
+            double latitudeDegrees = location.getLatitude();
+            double longitudeDegrees = location.getLongitude();
+            double altitudeMeters = location.getAltitude();
+            float speedMetersPerSec = location.getSpeed();
+            float bearingDegrees = location.getBearing();
+            float horizontalAccuracyMeters = location.getAccuracy();
+            float verticalAccuracyMeters = location.getVerticalAccuracyMeters();
+            float speedAccuracyMetersPerSecond = location.getSpeedAccuracyMetersPerSecond();
+            float bearingAccuracyDegrees = location.getBearingAccuracyDegrees();
+            long timestamp = location.getTime();
+
+            int elapsedRealtimeFlags = GNSS_REALTIME_HAS_TIMESTAMP_NS
+                    | (location.hasElapsedRealtimeUncertaintyNanos()
+                    ? GNSS_REALTIME_HAS_TIME_UNCERTAINTY_NS : 0);
+            long elapsedRealtimeNanos = location.getElapsedRealtimeNanos();
+            double elapsedRealtimeUncertaintyNanos = location.getElapsedRealtimeUncertaintyNanos();
+
+            mGnssHal.injectLocation(gnssLocationFlags, latitudeDegrees, longitudeDegrees,
+                    altitudeMeters, speedMetersPerSec, bearingDegrees, horizontalAccuracyMeters,
+                    verticalAccuracyMeters, speedAccuracyMetersPerSecond, bearingAccuracyDegrees,
+                    timestamp, elapsedRealtimeFlags, elapsedRealtimeNanos,
+                    elapsedRealtimeUncertaintyNanos);
         }
     }
 
@@ -735,9 +765,10 @@
      * Starts measurement collection.
      */
     public boolean startMeasurementCollection(boolean enableFullTracking,
-            boolean enableCorrVecOutputs) {
+            boolean enableCorrVecOutputs, int intervalMillis) {
         Preconditions.checkState(mRegistered);
-        return mGnssHal.startMeasurementCollection(enableFullTracking, enableCorrVecOutputs);
+        return mGnssHal.startMeasurementCollection(enableFullTracking, enableCorrVecOutputs,
+                intervalMillis);
     }
 
     /**
@@ -1262,8 +1293,15 @@
             return native_read_nmea(buffer, bufferSize);
         }
 
-        protected void injectLocation(double latitude, double longitude, float accuracy) {
-            native_inject_location(latitude, longitude, accuracy);
+        protected void injectLocation(@GnssLocationFlags int gnssLocationFlags, double latitude,
+                double longitude, double altitude, float speed, float bearing,
+                float horizontalAccuracy, float verticalAccuracy, float speedAccuracy,
+                float bearingAccuracy, long timestamp, @GnssRealtimeFlags int elapsedRealtimeFlags,
+                long elapsedRealtimeNanos, double elapsedRealtimeUncertaintyNanos) {
+            native_inject_location(gnssLocationFlags, latitude, longitude, altitude, speed,
+                    bearing, horizontalAccuracy, verticalAccuracy, speedAccuracy, bearingAccuracy,
+                    timestamp, elapsedRealtimeFlags, elapsedRealtimeNanos,
+                    elapsedRealtimeUncertaintyNanos);
         }
 
         protected void injectBestLocation(@GnssLocationFlags int gnssLocationFlags, double latitude,
@@ -1310,8 +1348,9 @@
         }
 
         protected boolean startMeasurementCollection(boolean enableFullTracking,
-                boolean enableCorrVecOutputs) {
-            return native_start_measurement_collection(enableFullTracking, enableCorrVecOutputs);
+                boolean enableCorrVecOutputs, int intervalMillis) {
+            return native_start_measurement_collection(enableFullTracking, enableCorrVecOutputs,
+                    intervalMillis);
         }
 
         protected boolean stopMeasurementCollection() {
@@ -1436,8 +1475,13 @@
 
     // location injection APIs
 
-    private static native void native_inject_location(double latitude, double longitude,
-            float accuracy);
+    private static native void native_inject_location(
+            int gnssLocationFlags, double latitudeDegrees, double longitudeDegrees,
+            double altitudeMeters, float speedMetersPerSec, float bearingDegrees,
+            float horizontalAccuracyMeters, float verticalAccuracyMeters,
+            float speedAccuracyMetersPerSecond, float bearingAccuracyDegrees,
+            long timestamp, int elapsedRealtimeFlags, long elapsedRealtimeNanos,
+            double elapsedRealtimeUncertaintyNanos);
 
 
     private static native void native_inject_best_location(
@@ -1475,7 +1519,7 @@
     private static native boolean native_is_measurement_supported();
 
     private static native boolean native_start_measurement_collection(boolean enableFullTracking,
-            boolean enableCorrVecOutputs);
+            boolean enableCorrVecOutputs, int intervalMillis);
 
     private static native boolean native_stop_measurement_collection();
 
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 e696d1e..1ba32ac 100644
--- a/services/core/java/com/android/server/location/provider/LocationProviderManager.java
+++ b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
@@ -245,38 +245,19 @@
                 intent.putExtra(KEY_LOCATIONS, locationResult.asList().toArray(new Location[0]));
             }
 
-            PendingIntent.OnFinished onFinished = null;
-
-            // send() SHOULD only run the completion callback if it completes successfully. however,
-            // b/201299281 (which could not be fixed in the S timeframe) means that it's possible
-            // for send() to throw an exception AND run the completion callback. if this happens, we
-            // would over-release the wakelock... we take matters into our own hands to ensure that
-            // the completion callback can only be run if send() completes successfully. this means
-            // the completion callback may be run inline - but as we've never specified what thread
-            // the callback is run on, this is fine.
-            GatedCallback gatedCallback;
+            Runnable callback = null;
             if (onCompleteCallback != null) {
-                gatedCallback = new GatedCallback(() -> {
+                callback = () -> {
                     try {
                         onCompleteCallback.sendResult(null);
                     } catch (RemoteException e) {
                         throw e.rethrowFromSystemServer();
                     }
-                });
-                onFinished = (pI, i, rC, rD, rE) -> gatedCallback.run();
-            } else {
-                gatedCallback = new GatedCallback(null);
+                };
             }
 
-            mPendingIntent.send(
-                    mContext,
-                    0,
-                    intent,
-                    onFinished,
-                    null,
-                    null,
+            PendingIntentSender.send(mPendingIntent, mContext, intent, callback,
                     options.toBundle());
-            gatedCallback.allow();
         }
 
         @Override
@@ -1783,12 +1764,26 @@
 
         ICancellationSignal cancelTransport = CancellationSignal.createTransport();
         CancellationSignal.fromTransport(cancelTransport)
-                .setOnCancelListener(SingleUseCallback.wrap(
+                .setOnCancelListener(
                         () -> {
-                            synchronized (mLock) {
-                                removeRegistration(callback.asBinder(), registration);
+                            final long ident = Binder.clearCallingIdentity();
+                            try {
+                                synchronized (mLock) {
+                                    removeRegistration(callback.asBinder(), registration);
+                                }
+                            } catch (RuntimeException e) {
+                                // since this is within a oneway binder transaction there is nowhere
+                                // for exceptions to go - move onto another thread to crash system
+                                // server so we find out about it
+                                FgThread.getExecutor().execute(() -> {
+                                    throw new AssertionError(e);
+                                });
+                                throw e;
+                            } finally {
+                                Binder.restoreCallingIdentity(ident);
                             }
-                        }));
+
+                        });
         return cancelTransport;
     }
 
@@ -2733,103 +2728,84 @@
         }
     }
 
-    private static class SingleUseCallback extends IRemoteCallback.Stub implements Runnable,
-            CancellationSignal.OnCancelListener {
+    private static class PendingIntentSender {
 
-        public static @Nullable SingleUseCallback wrap(@Nullable Runnable callback) {
-            return callback == null ? null : new SingleUseCallback(callback);
-        }
-
-        @GuardedBy("this")
-        private @Nullable Runnable mCallback;
-
-        private SingleUseCallback(Runnable callback) {
-            mCallback = Objects.requireNonNull(callback);
-        }
-
-        @Override
-        public void sendResult(Bundle data) {
-            run();
-        }
-
-        @Override
-        public void onCancel() {
-            run();
-        }
-
-        @Override
-        public void run() {
-            Runnable callback;
-            synchronized (this) {
-                callback = mCallback;
-                mCallback = null;
+        // send() SHOULD only run the OnFinished callback if it completes successfully. however,
+        // b/201299281 (which could not be fixed in the S timeframe) means that it's possible
+        // for send() to throw an exception AND run the completion callback which breaks the
+        // guarantee we rely on. we take matters into our own hands to ensure that the OnFinished
+        // callback can only be run if send() completes successfully. this means the OnFinished
+        // callback may be run inline, so there is no longer any guarantee about what thread the
+        // callback will be run on.
+        public static void send(PendingIntent pendingIntent, Context context, Intent intent,
+                @Nullable final Runnable callback, Bundle options)
+                throws PendingIntent.CanceledException {
+            GatedCallback gatedCallback;
+            PendingIntent.OnFinished onFinished;
+            if (callback != null) {
+                gatedCallback = new GatedCallback(callback);
+                onFinished = (pI, i, rC, rD, rE) -> gatedCallback.run();
+            } else {
+                gatedCallback = null;
+                onFinished = null;
             }
 
-            // prevent this callback from being run more than once - otherwise this could provide an
-            // attack vector for a malicious app to break assumptions on how many times a callback
-            // may be invoked, and thus crash system server.
-            if (callback == null) {
-                return;
-            }
-
-            final long identity = Binder.clearCallingIdentity();
-            try {
-                callback.run();
-            } catch (RuntimeException e) {
-                // since this is within a oneway binder transaction there is nowhere
-                // for exceptions to go - move onto another thread to crash system
-                // server so we find out about it
-                FgThread.getExecutor().execute(() -> {
-                    throw new AssertionError(e);
-                });
-                throw e;
-            } finally {
-                Binder.restoreCallingIdentity(identity);
+            pendingIntent.send(
+                    context,
+                    0,
+                    intent,
+                    onFinished,
+                    null,
+                    null,
+                    options);
+            if (gatedCallback != null) {
+                gatedCallback.allow();
             }
         }
-    }
 
-    private static class GatedCallback implements Runnable {
+        private static class GatedCallback implements Runnable {
 
-        private @Nullable Runnable mCallback;
+            @GuardedBy("this")
+            private @Nullable Runnable mCallback;
 
-        @GuardedBy("this")
-        private boolean mGate;
-        @GuardedBy("this")
-        private boolean mRun;
+            @GuardedBy("this")
+            private boolean mGate;
+            @GuardedBy("this")
+            private boolean mRun;
 
-        GatedCallback(@Nullable Runnable callback) {
-            mCallback = callback;
-        }
+            private GatedCallback(@Nullable Runnable callback) {
+                mCallback = callback;
+            }
 
-        public void allow() {
-            Runnable callback = null;
-            synchronized (this) {
-                mGate = true;
-                if (mRun && mCallback != null) {
-                    callback = mCallback;
-                    mCallback = null;
+            public void allow() {
+                Runnable callback = null;
+                synchronized (this) {
+                    mGate = true;
+                    if (mRun && mCallback != null) {
+                        callback = mCallback;
+                        mCallback = null;
+                    }
+                }
+
+                if (callback != null) {
+                    callback.run();
                 }
             }
 
-            if (callback != null) {
-                callback.run();
-            }
-        }
-
-        @Override
-        public void run() {
-            Runnable callback = null;
-            synchronized (this) {
-                mRun = true;
-                if (mGate && mCallback != null) {
-                    callback = mCallback;
-                    mCallback = null;
+            @Override
+            public void run() {
+                Runnable callback = null;
+                synchronized (this) {
+                    mRun = true;
+                    if (mGate && mCallback != null) {
+                        callback = mCallback;
+                        mCallback = null;
+                    }
                 }
-            }
 
-            if (callback != null) {
-                callback.run();
+                if (callback != null) {
+                    callback.run();
+                }
             }
         }
     }
@@ -2846,10 +2822,25 @@
 
         @Override
         public void sendResult(Bundle data) {
+            final long identity = Binder.clearCallingIdentity();
             try {
                 mWakeLock.release();
             } catch (RuntimeException e) {
-                Log.e(TAG, "wakelock over-released by " + mIdentity, e);
+                // wakelock throws a RuntimeException instead of some more specific exception, so
+                // attempt to capture only actual RuntimeExceptions
+                if (e.getClass() == RuntimeException.class) {
+                    Log.e(TAG, "wakelock over-released by " + mIdentity, e);
+                } else {
+                    // since this is within a oneway binder transaction there is nowhere for
+                    // exceptions to go - move onto another thread to crash system server so we find
+                    // out about it
+                    FgThread.getExecutor().execute(() -> {
+                        throw new AssertionError(e);
+                    });
+                    throw e;
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
             }
         }
     }
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index bf50db8..65c5b88 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -255,6 +255,7 @@
 import com.android.internal.util.StatLogger;
 import com.android.internal.util.XmlUtils;
 import com.android.net.module.util.NetworkIdentityUtils;
+import com.android.net.module.util.NetworkStatsUtils;
 import com.android.net.module.util.PermissionUtils;
 import com.android.server.EventLogTags;
 import com.android.server.LocalServices;
@@ -2004,7 +2005,7 @@
         for (final NetworkStateSnapshot snapshot : snapshots) {
             mNetIdToSubId.put(snapshot.getNetwork().getNetId(), parseSubId(snapshot));
 
-            // Policies matched by NPMS only match by subscriber ID or by ssid. Thus subtype
+            // Policies matched by NPMS only match by subscriber ID or by network ID. Thus subtype
             // in the object created here is never used and its value doesn't matter, so use
             // NETWORK_TYPE_UNKNOWN.
             final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, snapshot,
@@ -2368,7 +2369,8 @@
                             templateMeteredness = readIntAttribute(in, ATTR_TEMPLATE_METERED);
 
                         } else {
-                            subscriberIdMatchRule = NetworkTemplate.SUBSCRIBER_ID_MATCH_RULE_EXACT;
+                            subscriberIdMatchRule =
+                                    NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT;
                             if (templateType == MATCH_MOBILE) {
                                 Log.d(TAG, "Update template match rule from mobile to carrier and"
                                         + " force to metered");
@@ -2431,12 +2433,20 @@
                         } else {
                             inferred = false;
                         }
-                        final NetworkTemplate template = new NetworkTemplate(templateType,
-                                subscriberId, new String[] { subscriberId },
-                                networkId, templateMeteredness, NetworkStats.ROAMING_ALL,
-                                NetworkStats.DEFAULT_NETWORK_ALL, NetworkTemplate.NETWORK_TYPE_ALL,
-                                NetworkTemplate.OEM_MANAGED_ALL, subscriberIdMatchRule);
-                        if (template.isPersistable()) {
+                        final NetworkTemplate.Builder builder =
+                                new NetworkTemplate.Builder(templateType)
+                                        .setMeteredness(templateMeteredness);
+                        if (subscriberIdMatchRule
+                                == NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT) {
+                            final ArraySet<String> ids = new ArraySet<>();
+                            ids.add(subscriberId);
+                            builder.setSubscriberIds(ids);
+                        }
+                        if (networkId != null) {
+                            builder.setWifiNetworkKeys(Set.of(networkId));
+                        }
+                        final NetworkTemplate template = builder.build();
+                        if (NetworkPolicy.isTemplatePersistable(template)) {
                             mNetworkPolicy.put(template, new NetworkPolicy(template, cycleRule,
                                     warningBytes, limitBytes, lastWarningSnooze,
                                     lastLimitSnooze, metered, inferred));
@@ -2585,35 +2595,39 @@
      * into {@link WifiConfiguration}.
      */
     private void upgradeWifiMeteredOverride() {
-        final ArrayMap<String, Boolean> wifiNetworkIds = new ArrayMap<>();
+        final ArrayMap<String, Boolean> wifiNetworkKeys = new ArrayMap<>();
         synchronized (mNetworkPoliciesSecondLock) {
             for (int i = 0; i < mNetworkPolicy.size();) {
                 final NetworkPolicy policy = mNetworkPolicy.valueAt(i);
                 if (policy.template.getMatchRule() == NetworkTemplate.MATCH_WIFI
                         && !policy.inferred) {
                     mNetworkPolicy.removeAt(i);
-                    wifiNetworkIds.put(policy.template.getNetworkId(), policy.metered);
+                    final Set<String> keys = policy.template.getWifiNetworkKeys();
+                    wifiNetworkKeys.put(keys.isEmpty() ? null : keys.iterator().next(),
+                            policy.metered);
                 } else {
                     i++;
                 }
             }
         }
 
-        if (wifiNetworkIds.isEmpty()) {
+        if (wifiNetworkKeys.isEmpty()) {
             return;
         }
         final WifiManager wm = mContext.getSystemService(WifiManager.class);
         final List<WifiConfiguration> configs = wm.getConfiguredNetworks();
         for (int i = 0; i < configs.size(); ++i) {
             final WifiConfiguration config = configs.get(i);
-            final String networkId = resolveNetworkId(config);
-            final Boolean metered = wifiNetworkIds.get(networkId);
-            if (metered != null) {
-                Slog.d(TAG, "Found network " + networkId + "; upgrading metered hint");
-                config.meteredOverride = metered
-                        ? WifiConfiguration.METERED_OVERRIDE_METERED
-                        : WifiConfiguration.METERED_OVERRIDE_NOT_METERED;
-                wm.updateNetwork(config);
+            for (String key : config.getAllPersistableNetworkKeys()) {
+                final Boolean metered = wifiNetworkKeys.get(key);
+                if (metered != null) {
+                    Slog.d(TAG, "Found network " + key + "; upgrading metered hint");
+                    config.meteredOverride = metered
+                            ? WifiConfiguration.METERED_OVERRIDE_METERED
+                            : WifiConfiguration.METERED_OVERRIDE_NOT_METERED;
+                    wm.updateNetwork(config);
+                    break;
+                }
             }
         }
 
@@ -2643,7 +2657,7 @@
             for (int i = 0; i < mNetworkPolicy.size(); i++) {
                 final NetworkPolicy policy = mNetworkPolicy.valueAt(i);
                 final NetworkTemplate template = policy.template;
-                if (!template.isPersistable()) continue;
+                if (!NetworkPolicy.isTemplatePersistable(template)) continue;
 
                 out.startTag(null, TAG_NETWORK_POLICY);
                 writeIntAttribute(out, ATTR_NETWORK_TEMPLATE, template.getMatchRule());
@@ -2651,11 +2665,13 @@
                 if (subscriberId != null) {
                     out.attribute(null, ATTR_SUBSCRIBER_ID, subscriberId);
                 }
-                writeIntAttribute(out, ATTR_SUBSCRIBER_ID_MATCH_RULE,
-                        template.getSubscriberIdMatchRule());
-                final String networkId = template.getNetworkId();
-                if (networkId != null) {
-                    out.attribute(null, ATTR_NETWORK_ID, networkId);
+                final int subscriberIdMatchRule = template.getSubscriberIds().isEmpty()
+                        ? NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_ALL
+                        : NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT;
+                writeIntAttribute(out, ATTR_SUBSCRIBER_ID_MATCH_RULE, subscriberIdMatchRule);
+                if (!template.getWifiNetworkKeys().isEmpty()) {
+                    out.attribute(null, ATTR_NETWORK_ID,
+                            template.getWifiNetworkKeys().iterator().next());
                 }
                 writeIntAttribute(out, ATTR_TEMPLATE_METERED,
                         template.getMeteredness());
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 137fc85..2068632 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -7871,7 +7871,9 @@
 
             int index = mToastQueue.indexOf(record);
             if (index >= 0) {
-                mToastQueue.remove(index);
+                ToastRecord toast = mToastQueue.remove(index);
+                mWindowManagerInternal.removeWindowToken(
+                        toast.windowToken, true /* removeWindows */, toast.displayId);
             }
             record = (mToastQueue.size() > 0) ? mToastQueue.get(0) : null;
         }
diff --git a/services/core/java/com/android/server/pm/AppDataHelper.java b/services/core/java/com/android/server/pm/AppDataHelper.java
index bedb8b9..22cd06d 100644
--- a/services/core/java/com/android/server/pm/AppDataHelper.java
+++ b/services/core/java/com/android/server/pm/AppDataHelper.java
@@ -101,6 +101,12 @@
             mPm.mSettings.writeKernelMappingLPr(ps);
         }
 
+        // TODO(b/211761016): should we still create the profile dirs?
+        if (!shouldHaveAppStorage(pkg)) {
+            Slog.w(TAG, "Skipping preparing app data for " + pkg.getPackageName());
+            return;
+        }
+
         Installer.Batch batch = new Installer.Batch();
         UserManagerInternal umInternal = mInjector.getUserManagerInternal();
         StorageManagerInternal smInternal = mInjector.getLocalService(
@@ -161,6 +167,10 @@
             Slog.wtf(TAG, "Package was null!", new Throwable());
             return CompletableFuture.completedFuture(null);
         }
+        if (!shouldHaveAppStorage(pkg)) {
+            Slog.w(TAG, "Skipping preparing app data for " + pkg.getPackageName());
+            return CompletableFuture.completedFuture(null);
+        }
         return prepareAppDataLeaf(batch, pkg, previousAppId, userId, flags);
     }
 
@@ -381,7 +391,7 @@
             for (File file : files) {
                 final String packageName = file.getName();
                 try {
-                    assertPackageKnownAndInstalled(volumeUuid, packageName, userId);
+                    assertPackageStorageValid(volumeUuid, packageName, userId);
                 } catch (PackageManagerException e) {
                     logCriticalInfo(Log.WARN, "Destroying " + file + " due to: " + e);
                     try {
@@ -398,7 +408,7 @@
             for (File file : files) {
                 final String packageName = file.getName();
                 try {
-                    assertPackageKnownAndInstalled(volumeUuid, packageName, userId);
+                    assertPackageStorageValid(volumeUuid, packageName, userId);
                 } catch (PackageManagerException e) {
                     logCriticalInfo(Log.WARN, "Destroying " + file + " due to: " + e);
                     try {
@@ -446,7 +456,11 @@
         return result;
     }
 
-    private void assertPackageKnownAndInstalled(String volumeUuid, String packageName, int userId)
+    /**
+     * Asserts that storage path is valid by checking that {@code packageName} is present,
+     * installed for the given {@code userId} and can have app data.
+     */
+    private void assertPackageStorageValid(String volumeUuid, String packageName, int userId)
             throws PackageManagerException {
         synchronized (mPm.mLock) {
             // Normalize package name to handle renamed packages
@@ -462,6 +476,13 @@
             } else if (!ps.getInstalled(userId)) {
                 throw new PackageManagerException(
                         "Package " + packageName + " not installed for user " + userId);
+            } else if (ps.getPkg() == null) {
+                throw new PackageManagerException("Package " + packageName + " is not parsed yet");
+            } else {
+                if (!shouldHaveAppStorage(ps.getPkg())) {
+                    throw new PackageManagerException(
+                            "Package " + packageName + " shouldn't have storage");
+                }
             }
         }
     }
@@ -603,4 +624,13 @@
             Slog.w(TAG, String.valueOf(e));
         }
     }
+
+    /**
+     * Returns {@code true} if app's internal storage should be created for this {@code pkg}.
+     */
+    private boolean shouldHaveAppStorage(AndroidPackage pkg) {
+        PackageManager.Property noAppDataProp =
+                pkg.getProperties().get(PackageManager.PROPERTY_NO_APP_DATA_STORAGE);
+        return noAppDataProp == null || !noAppDataProp.getBoolean();
+    }
 }
diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java
index 1945ed0..2f4f271 100644
--- a/services/core/java/com/android/server/pm/ComputerEngine.java
+++ b/services/core/java/com/android/server/pm/ComputerEngine.java
@@ -146,7 +146,6 @@
 import com.android.server.pm.verify.domain.DomainVerificationUtils;
 import com.android.server.uri.UriGrantsManagerInternal;
 import com.android.server.utils.WatchedArrayMap;
-import com.android.server.utils.WatchedArraySet;
 import com.android.server.utils.WatchedLongSparseArray;
 import com.android.server.utils.WatchedSparseBooleanArray;
 import com.android.server.utils.WatchedSparseIntArray;
@@ -321,10 +320,7 @@
     private final WatchedArrayMap<String, AndroidPackage> mPackages;
     private final WatchedArrayMap<ComponentName, ParsedInstrumentation>
             mInstrumentation;
-    private final WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>>
-            mStaticLibsByDeclaringPackage;
-    private final WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>>
-            mSharedLibraries;
+    private final SharedLibrariesRead mSharedLibraries;
     private final ComponentName mLocalResolveComponentName;
     private final ActivityInfo mResolveActivity;
     private final WatchedSparseBooleanArray mWebInstantAppsDisabled;
@@ -333,7 +329,7 @@
     private final InstantAppRegistry mInstantAppRegistry;
     private final ApplicationInfo mLocalAndroidApplication;
     private final AppsFilter mAppsFilter;
-    private final WatchedArraySet<String> mFrozenPackages;
+    private final WatchedArrayMap<String, Integer> mFrozenPackages;
 
     // Immutable service attribute
     private final String mAppPredictionServicePackage;
@@ -376,8 +372,7 @@
         mSettings = new Settings(args.settings);
         mIsolatedOwners = args.isolatedOwners;
         mPackages = args.packages;
-        mSharedLibraries = args.sharedLibs;
-        mStaticLibsByDeclaringPackage = args.staticLibs;
+        mSharedLibraries = args.sharedLibraries;
         mInstrumentation = args.instrumentation;
         mWebInstantAppsDisabled = args.webInstantAppsDisabled;
         mLocalResolveComponentName = args.resolveComponentName;
@@ -1565,7 +1560,7 @@
                     : mPermissionManager.getGrantedPermissions(ps.getPackageName(), userId);
 
             PackageInfo packageInfo = PackageInfoUtils.generate(p, gids, flags,
-                    ps.getFirstInstallTime(), ps.getLastUpdateTime(), permissions, state, userId,
+                    state.getFirstInstallTime(), ps.getLastUpdateTime(), permissions, state, userId,
                     ps);
 
             if (packageInfo == null) {
@@ -1582,7 +1577,7 @@
             pi.packageName = ps.getPackageName();
             pi.setLongVersionCode(ps.getVersionCode());
             pi.sharedUserId = (ps.getSharedUser() != null) ? ps.getSharedUser().name : null;
-            pi.firstInstallTime = ps.getFirstInstallTime();
+            pi.firstInstallTime = state.getFirstInstallTime();
             pi.lastUpdateTime = ps.getLastUpdateTime();
 
             ApplicationInfo ai = new ApplicationInfo();
@@ -2007,8 +2002,7 @@
 
     @Nullable
     public final SharedLibraryInfo getSharedLibraryInfo(String name, long version) {
-        return SharedLibraryHelper.getSharedLibraryInfo(
-                name, version, mSharedLibraries, null);
+        return mSharedLibraries.getSharedLibraryInfo(name, version);
     }
 
     /**
@@ -2059,7 +2053,7 @@
 
         // Is this a static library?
         WatchedLongSparseArray<SharedLibraryInfo> versionedLib =
-                mStaticLibsByDeclaringPackage.get(packageName);
+                mSharedLibraries.getStaticLibraryInfos(packageName);
         if (versionedLib == null || versionedLib.size() <= 0) {
             return packageName;
         }
@@ -3057,54 +3051,8 @@
             }
 
             case DumpState.DUMP_LIBS:
-            {
-                boolean printedHeader = false;
-                final int numSharedLibraries = mSharedLibraries.size();
-                for (int index = 0; index < numSharedLibraries; index++) {
-                    final String libName = mSharedLibraries.keyAt(index);
-                    final WatchedLongSparseArray<SharedLibraryInfo> versionedLib =
-                            mSharedLibraries.get(libName);
-                    if (versionedLib == null) {
-                        continue;
-                    }
-                    final int versionCount = versionedLib.size();
-                    for (int i = 0; i < versionCount; i++) {
-                        SharedLibraryInfo libraryInfo = versionedLib.valueAt(i);
-                        if (!checkin) {
-                            if (!printedHeader) {
-                                if (dumpState.onTitlePrinted()) {
-                                    pw.println();
-                                }
-                                pw.println("Libraries:");
-                                printedHeader = true;
-                            }
-                            pw.print("  ");
-                        } else {
-                            pw.print("lib,");
-                        }
-                        pw.print(libraryInfo.getName());
-                        if (libraryInfo.isStatic()) {
-                            pw.print(" version=" + libraryInfo.getLongVersion());
-                        }
-                        if (!checkin) {
-                            pw.print(" -> ");
-                        }
-                        if (libraryInfo.getPath() != null) {
-                            if (libraryInfo.isNative()) {
-                                pw.print(" (so) ");
-                            } else {
-                                pw.print(" (jar) ");
-                            }
-                            pw.print(libraryInfo.getPath());
-                        } else {
-                            pw.print(" (apk) ");
-                            pw.print(libraryInfo.getPackageName());
-                        }
-                        pw.println();
-                    }
-                }
+                mSharedLibraries.dump(pw, dumpState);
                 break;
-            }
 
             case DumpState.DUMP_PREFERRED:
                 mSettings.dumpPreferred(pw, dumpState, packageName);
@@ -3545,7 +3493,7 @@
     @NonNull
     @Override
     public WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>> getSharedLibraries() {
-        return mSharedLibraries;
+        return mSharedLibraries.getAll();
     }
 
     @NonNull
@@ -3580,7 +3528,7 @@
             return PackageManagerService.PACKAGE_STARTABILITY_NOT_SYSTEM;
         }
 
-        if (mFrozenPackages.contains(packageName)) {
+        if (mFrozenPackages.containsKey(packageName)) {
             return PackageManagerService.PACKAGE_STARTABILITY_FROZEN;
         }
 
@@ -5488,12 +5436,11 @@
             }
             PackageDexUsage.PackageUseInfo packageUseInfo =
                     mDexManager.getPackageUseInfoOrDefault(packageState.getPackageName());
-            if (PackageManagerServiceUtils
-                    .isUnusedSinceTimeInMillis(packageState.getFirstInstallTime(),
-                            currentTimeInMillis, downgradeTimeThresholdMillis, packageUseInfo,
-                            packageState.getTransientState().getLatestPackageUseTimeInMills(),
-                            packageState.getTransientState()
-                                    .getLatestForegroundPackageUseTimeInMills())) {
+            if (PackageManagerServiceUtils.isUnusedSinceTimeInMillis(
+                    PackageStateUtils.getEarliestFirstInstallTime(packageState.getUserStates()),
+                    currentTimeInMillis, downgradeTimeThresholdMillis, packageUseInfo,
+                    packageState.getTransientState().getLatestPackageUseTimeInMills(),
+                    packageState.getTransientState().getLatestForegroundPackageUseTimeInMills())) {
                 unusedPackages.add(packageState.getPackageName());
             }
         }
diff --git a/services/core/java/com/android/server/pm/DeletePackageHelper.java b/services/core/java/com/android/server/pm/DeletePackageHelper.java
index e84d990..9a80a4e 100644
--- a/services/core/java/com/android/server/pm/DeletePackageHelper.java
+++ b/services/core/java/com/android/server/pm/DeletePackageHelper.java
@@ -547,7 +547,6 @@
                     true /*notLaunched*/,
                     false /*hidden*/,
                     0 /*distractionFlags*/,
-                    false /*suspended*/,
                     null /*suspendParams*/,
                     false /*instantApp*/,
                     false /*virtualPreload*/,
@@ -557,7 +556,8 @@
                     PackageManager.INSTALL_REASON_UNKNOWN,
                     PackageManager.UNINSTALL_REASON_UNKNOWN,
                     null /*harmfulAppWarning*/,
-                    null /*splashScreenTheme*/);
+                    null /*splashScreenTheme*/,
+                    0 /*firstInstallTime*/);
         }
         mPm.mSettings.writeKernelMappingLPr(ps);
     }
diff --git a/services/core/java/com/android/server/pm/DumpHelper.java b/services/core/java/com/android/server/pm/DumpHelper.java
index c670e1f..55d1293 100644
--- a/services/core/java/com/android/server/pm/DumpHelper.java
+++ b/services/core/java/com/android/server/pm/DumpHelper.java
@@ -25,7 +25,6 @@
 import android.content.pm.FeatureInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
-import android.content.pm.SharedLibraryInfo;
 import android.os.Binder;
 import android.os.UserHandle;
 import android.os.incremental.PerUidReadTimeouts;
@@ -37,7 +36,6 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.pm.verify.domain.proxy.DomainVerificationProxy;
-import com.android.server.utils.WatchedLongSparseArray;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -504,6 +502,9 @@
                     ipw.println("(none)");
                 } else {
                     for (int i = 0; i < mPm.mFrozenPackages.size(); i++) {
+                        ipw.print("package=");
+                        ipw.print(mPm.mFrozenPackages.keyAt(i));
+                        ipw.print(", refCounts=");
                         ipw.println(mPm.mFrozenPackages.valueAt(i));
                     }
                 }
@@ -707,7 +708,7 @@
                 proto.end(verifierPackageToken);
             }
 
-            dumpSharedLibrariesProto(proto);
+            mPm.mInjector.getSharedLibrariesImpl().dumpProto(proto);
             dumpFeaturesProto(proto);
             mPm.mSettings.dumpPackagesProto(proto);
             mPm.mSettings.dumpSharedUsersProto(proto);
@@ -725,33 +726,4 @@
             }
         }
     }
-
-    private void dumpSharedLibrariesProto(ProtoOutputStream proto) {
-        final int count = mPm.mSharedLibraries.size();
-        for (int i = 0; i < count; i++) {
-            final String libName = mPm.mSharedLibraries.keyAt(i);
-            WatchedLongSparseArray<SharedLibraryInfo> versionedLib =
-                    mPm.mSharedLibraries.get(libName);
-            if (versionedLib == null) {
-                continue;
-            }
-            final int versionCount = versionedLib.size();
-            for (int j = 0; j < versionCount; j++) {
-                final SharedLibraryInfo libraryInfo = versionedLib.valueAt(j);
-                final long sharedLibraryToken =
-                        proto.start(PackageServiceDumpProto.SHARED_LIBRARIES);
-                proto.write(PackageServiceDumpProto.SharedLibraryProto.NAME, libraryInfo.getName());
-                final boolean isJar = (libraryInfo.getPath() != null);
-                proto.write(PackageServiceDumpProto.SharedLibraryProto.IS_JAR, isJar);
-                if (isJar) {
-                    proto.write(PackageServiceDumpProto.SharedLibraryProto.PATH,
-                            libraryInfo.getPath());
-                } else {
-                    proto.write(PackageServiceDumpProto.SharedLibraryProto.APK,
-                            libraryInfo.getPackageName());
-                }
-                proto.end(sharedLibraryToken);
-            }
-        }
-    }
 }
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index 8e6746d..27b6282 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -207,6 +207,7 @@
     private final PackageAbiHelper mPackageAbiHelper;
     private final ViewCompiler mViewCompiler;
     private final IBackupManager mIBackupManager;
+    private final SharedLibrariesImpl mSharedLibraries;
 
     // TODO(b/198166813): remove PMS dependency
     InstallPackageHelper(PackageManagerService pm, AppDataHelper appDataHelper) {
@@ -226,6 +227,7 @@
         mPackageAbiHelper = pm.mInjector.getAbiHelper();
         mViewCompiler = pm.mInjector.getViewCompiler();
         mIBackupManager = pm.mInjector.getIBackupManager();
+        mSharedLibraries = pm.mInjector.getSharedLibrariesImpl();
     }
 
     InstallPackageHelper(PackageManagerService pm) {
@@ -325,7 +327,7 @@
         }
 
         if (reconciledPkg.mCollectedSharedLibraryInfos != null) {
-            mPm.executeSharedLibrariesUpdateLPr(pkg, pkgSetting, null, null,
+            mSharedLibraries.executeSharedLibrariesUpdateLPw(pkg, pkgSetting, null, null,
                     reconciledPkg.mCollectedSharedLibraryInfos, allUsers);
         }
 
@@ -388,13 +390,13 @@
         synchronized (mPm.mLock) {
             if (!ArrayUtils.isEmpty(reconciledPkg.mAllowedSharedLibraryInfos)) {
                 for (SharedLibraryInfo info : reconciledPkg.mAllowedSharedLibraryInfos) {
-                    mPm.commitSharedLibraryInfoLocked(info);
+                    mSharedLibraries.commitSharedLibraryInfoLPw(info);
                 }
                 final Map<String, AndroidPackage> combinedSigningDetails =
                         reconciledPkg.getCombinedAvailablePackages();
                 try {
                     // Shared libraries for the package need to be updated.
-                    mPm.updateSharedLibrariesLocked(pkg, pkgSetting, null, null,
+                    mSharedLibraries.updateSharedLibrariesLPw(pkg, pkgSetting, null, null,
                             combinedSigningDetails);
                 } catch (PackageManagerException e) {
                     Slog.e(TAG, "updateSharedLibrariesLPr failed: ", e);
@@ -402,7 +404,7 @@
                 // Update all applications that use this library. Skip when booting
                 // since this will be done after all packages are scaned.
                 if ((scanFlags & SCAN_BOOTING) == 0) {
-                    clientLibPkgs = mPm.updateAllSharedLibrariesLocked(pkg, pkgSetting,
+                    clientLibPkgs = mSharedLibraries.updateAllSharedLibrariesLPw(pkg, pkgSetting,
                             combinedSigningDetails);
                 }
             }
@@ -559,6 +561,7 @@
                     pkgSetting.setHidden(false, userId);
                     pkgSetting.setInstallReason(installReason, userId);
                     pkgSetting.setUninstallReason(PackageManager.UNINSTALL_REASON_UNKNOWN, userId);
+                    pkgSetting.setFirstInstallTime(System.currentTimeMillis(), userId);
                     mPm.mSettings.writePackageRestrictionsLPr(userId);
                     mPm.mSettings.writeKernelMappingLPr(pkgSetting);
                     installed = true;
@@ -855,7 +858,7 @@
         mPm.notifyInstallObserver(request.mInstallResult, request.mArgs.mObserver);
     }
 
-    @GuardedBy("mInstallLock")
+    @GuardedBy("mPm.mInstallLock")
     private void installPackagesTracedLI(List<InstallRequest> requests) {
         try {
             Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackages");
@@ -884,7 +887,7 @@
      *
      * Failure at any phase will result in a full failure to install all packages.
      */
-    @GuardedBy("mInstallLock")
+    @GuardedBy("mPm.mInstallLock")
     private void installPackagesLI(List<InstallRequest> requests) {
         final Map<String, ScanResult> preparedScans = new ArrayMap<>(requests.size());
         final Map<String, InstallArgs> installArgs = new ArrayMap<>(requests.size());
@@ -939,17 +942,26 @@
                     if (result.needsNewAppId()) {
                         request.mInstallResult.mRemovedInfo.mAppIdChanging = true;
                     }
+                    if (!checkNoAppStorageIsConsistent(
+                            result.mRequest.mOldPkg, result.mPkgSetting.getPkg())) {
+                        // TODO: INSTALL_FAILED_UPDATE_INCOMPATIBLE is about incomptabible
+                        //  signatures. Is there a better error code?
+                        request.mInstallResult.setError(
+                                INSTALL_FAILED_UPDATE_INCOMPATIBLE,
+                                "Update attempted to change value of "
+                                        + PackageManager.PROPERTY_NO_APP_DATA_STORAGE);
+                        return;
+                    }
                     createdAppId.put(packageName, optimisticallyRegisterAppId(result));
                     versionInfos.put(result.mPkgSetting.getPkg().getPackageName(),
                             mPm.getSettingsVersionForPackage(result.mPkgSetting.getPkg()));
-                    if (result.mStaticSharedLibraryInfo != null
-                            || result.mSdkSharedLibraryInfo != null) {
-                        final PackageSetting sharedLibLatestVersionSetting =
-                                mPm.getSharedLibLatestVersionSetting(result);
-                        if (sharedLibLatestVersionSetting != null) {
+                    if (result.mStaticSharedLibraryInfo != null) {
+                        final PackageSetting staticSharedLibLatestVersionSetting =
+                                mSharedLibraries.getStaticSharedLibLatestVersionSetting(result);
+                        if (staticSharedLibLatestVersionSetting != null) {
                             lastStaticSharedLibSettings.put(
                                     result.mPkgSetting.getPkg().getPackageName(),
-                                    sharedLibLatestVersionSetting);
+                                    staticSharedLibLatestVersionSetting);
                         }
                     }
                 } catch (PackageManagerException e) {
@@ -961,7 +973,7 @@
                     reconcileRequest = new ReconcileRequest(preparedScans, installArgs,
                     installResults,
                     prepareResults,
-                    mPm.mSharedLibraries,
+                    mSharedLibraries.getAll(),
                     Collections.unmodifiableMap(mPm.mPackages), versionInfos,
                     lastStaticSharedLibSettings);
             CommitRequest commitRequest = null;
@@ -1036,7 +1048,23 @@
         }
     }
 
-    @GuardedBy("mInstallLock")
+    @GuardedBy("mPm.mInstallLock")
+    private boolean checkNoAppStorageIsConsistent(AndroidPackage oldPkg, AndroidPackage newPkg) {
+        if (oldPkg == null) {
+            // New install, nothing to check against.
+            return true;
+        }
+        final PackageManager.Property curProp =
+                oldPkg.getProperties().get(PackageManager.PROPERTY_NO_APP_DATA_STORAGE);
+        final PackageManager.Property newProp =
+                newPkg.getProperties().get(PackageManager.PROPERTY_NO_APP_DATA_STORAGE);
+        if (curProp == null || !curProp.getBoolean()) {
+            return newProp == null || !newProp.getBoolean();
+        }
+        return newProp != null && newProp.getBoolean();
+    }
+
+    @GuardedBy("mPm.mInstallLock")
     private PrepareResult preparePackageLI(InstallArgs args, PackageInstalledInfo res)
             throws PrepareFailure {
         final int installFlags = args.mInstallFlags;
@@ -1207,7 +1235,7 @@
                 // the package setting for the latest library version.
                 PackageSetting signatureCheckPs = ps;
                 if (parsedPackage.isStaticSharedLibrary()) {
-                    SharedLibraryInfo libraryInfo = mPm.getLatestSharedLibraVersionLPr(
+                    SharedLibraryInfo libraryInfo = mSharedLibraries.getLatestSharedLibraVersionLPr(
                             parsedPackage);
                     if (libraryInfo != null) {
                         signatureCheckPs = mPm.mSettings.getPackageLPr(
@@ -1880,7 +1908,7 @@
         }
     }
 
-    @GuardedBy("mLock")
+    @GuardedBy("mPm.mLock")
     private void commitPackagesLocked(final CommitRequest request) {
         // TODO: remove any expected failures from this method; this should only be able to fail due
         //       to unavoidable errors (I/O, etc.)
@@ -1900,7 +1928,7 @@
                 PackageStateInternal deletedPkgSetting = mPm.getPackageStateInternal(
                         oldPackage.getPackageName());
                 reconciledPkg.mPkgSetting
-                        .setFirstInstallTime(deletedPkgSetting.getFirstInstallTime())
+                        .setFirstInstallTimeFromReplaced(deletedPkgSetting, request.mAllUsers)
                         .setLastUpdateTime(System.currentTimeMillis());
 
                 res.mRemovedInfo.mBroadcastAllowList = mPm.mAppsFilter.getVisibilityAllowList(
@@ -1997,7 +2025,7 @@
         ApplicationPackageManager.invalidateGetPackagesForUidCache();
     }
 
-    @GuardedBy("mLock")
+    @GuardedBy("mPm.mLock")
     private boolean disableSystemPackageLPw(AndroidPackage oldPkg) {
         return mPm.mSettings.disableSystemPackageLPw(oldPkg.getPackageName(), true);
     }
@@ -2969,7 +2997,8 @@
                 synchronized (mPm.mLock) {
                     mAppDataHelper.prepareAppDataAfterInstallLIF(pkg);
                     try {
-                        mPm.updateSharedLibrariesLocked(pkg, stubPkgSetting, null, null,
+                        mSharedLibraries.updateSharedLibrariesLPw(
+                                pkg, stubPkgSetting, null, null,
                                 Collections.unmodifiableMap(mPm.mPackages));
                     } catch (PackageManagerException e) {
                         Slog.w(TAG, "updateAllSharedLibrariesLPw failed: ", e);
@@ -2992,7 +3021,8 @@
                     installPackageFromSystemLIF(stubPkg.getPath(),
                             mPm.mUserManager.getUserIds() /*allUserHandles*/,
                             null /*origUserHandles*/,
-                            true /*writeSettings*/);
+                            true /*writeSettings*/,
+                            Process.INVALID_UID /*previousAppId*/);
                 } catch (PackageManagerException pme) {
                     // Serious WTF; we have to be able to install the stub
                     Slog.wtf(TAG, "Failed to restore system package:" + stubPkg.getPackageName(),
@@ -3118,8 +3148,11 @@
             if (DEBUG_REMOVE) Slog.d(TAG, "Re-installing system package: " + disabledPs);
             try {
                 synchronized (mPm.mInstallLock) {
+                    final int[] origUsers = outInfo == null ? null : outInfo.mOrigUsers;
+                    final int previousAppId = disabledPs.getAppId() != deletedPs.getAppId()
+                            ? deletedPs.getAppId() : Process.INVALID_UID;
                     installPackageFromSystemLIF(disabledPs.getPathString(), allUserHandles,
-                            outInfo == null ? null : outInfo.mOrigUsers, writeSettings);
+                            origUsers, writeSettings, previousAppId);
                 }
             } catch (PackageManagerException e) {
                 Slog.w(TAG, "Failed to restore system package:" + deletedPs.getPackageName() + ": "
@@ -3160,7 +3193,8 @@
      */
     @GuardedBy({"mPm.mLock", "mPm.mInstallLock"})
     private void installPackageFromSystemLIF(@NonNull String codePathString,
-            @NonNull int[] allUserHandles, @Nullable int[] origUserHandles, boolean writeSettings)
+            @NonNull int[] allUserHandles, @Nullable int[] origUserHandles,
+            boolean writeSettings, int previousAppId)
             throws PackageManagerException {
         final File codePath = new File(codePathString);
         @ParsingPackageUtils.ParseFlags int parseFlags =
@@ -3175,7 +3209,7 @@
 
         try {
             // update shared libraries for the newly re-installed system package
-            mPm.updateSharedLibrariesLocked(pkg, pkgSetting, null, null,
+            mSharedLibraries.updateSharedLibrariesLPw(pkg, pkgSetting, null, null,
                     Collections.unmodifiableMap(mPm.mPackages));
         } catch (PackageManagerException e) {
             Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage());
@@ -3184,11 +3218,12 @@
         mAppDataHelper.prepareAppDataAfterInstallLIF(pkg);
 
         setPackageInstalledForSystemPackage(pkg, allUserHandles,
-                origUserHandles, writeSettings);
+                origUserHandles, writeSettings, previousAppId);
     }
 
     private void setPackageInstalledForSystemPackage(@NonNull AndroidPackage pkg,
-            @NonNull int[] allUserHandles, @Nullable int[] origUserHandles, boolean writeSettings) {
+            @NonNull int[] allUserHandles, @Nullable int[] origUserHandles,
+            boolean writeSettings, int previousAppId) {
         // writer
         synchronized (mPm.mLock) {
             PackageSetting ps = mPm.mSettings.getPackageLPr(pkg.getPackageName());
@@ -3222,8 +3257,7 @@
 
             // The method below will take care of removing obsolete permissions and granting
             // install permissions.
-            mPm.mPermissionManager.onPackageInstalled(pkg,
-                    Process.INVALID_UID /* previousAppId */,
+            mPm.mPermissionManager.onPackageInstalled(pkg, previousAppId,
                     PermissionManagerServiceInternal.PackageInstalledParams.DEFAULT,
                     UserHandle.USER_ALL);
             for (final int userId : allUserHandles) {
@@ -3550,23 +3584,20 @@
                 boolean appIdCreated = false;
                 try {
                     final String pkgName = scanResult.mPkgSetting.getPackageName();
+                    final ReconcileRequest reconcileRequest = new ReconcileRequest(
+                            Collections.singletonMap(pkgName, scanResult),
+                            mSharedLibraries.getAll(), mPm.mPackages,
+                            Collections.singletonMap(pkgName,
+                                    mPm.getSettingsVersionForPackage(parsedPackage)),
+                            Collections.singletonMap(pkgName,
+                                    mSharedLibraries.getStaticSharedLibLatestVersionSetting(
+                                            scanResult)));
                     final Map<String, ReconciledPackage> reconcileResult =
-                            ReconcilePackageUtils.reconcilePackages(
-                                    new ReconcileRequest(
-                                            Collections.singletonMap(pkgName, scanResult),
-                                            mPm.mSharedLibraries,
-                                            mPm.mPackages,
-                                            Collections.singletonMap(
-                                                    pkgName,
-                                                    mPm.getSettingsVersionForPackage(
-                                                            parsedPackage)),
-                                            Collections.singletonMap(pkgName,
-                                                    mPm.getSharedLibLatestVersionSetting(
-                                                            scanResult))),
+                            ReconcilePackageUtils.reconcilePackages(reconcileRequest,
                                     mPm.mSettings.getKeySetManagerService(), mPm.mInjector);
                     appIdCreated = optimisticallyRegisterAppId(scanResult);
-                    commitReconciledScanResultLocked(
-                            reconcileResult.get(pkgName), mPm.mUserManager.getUserIds());
+                    commitReconciledScanResultLocked(reconcileResult.get(pkgName),
+                            mPm.mUserManager.getUserIds());
                 } catch (PackageManagerException e) {
                     if (appIdCreated) {
                         cleanUpAppIdCreation(scanResult);
@@ -4187,8 +4218,8 @@
         long minVersionCode = Long.MIN_VALUE;
         long maxVersionCode = Long.MAX_VALUE;
 
-        WatchedLongSparseArray<SharedLibraryInfo> versionedLib = mPm.mSharedLibraries.get(
-                pkg.getStaticSharedLibName());
+        WatchedLongSparseArray<SharedLibraryInfo> versionedLib =
+                mSharedLibraries.getSharedLibraryInfos(pkg.getStaticSharedLibName());
         if (versionedLib != null) {
             final int versionCount = versionedLib.size();
             for (int i = 0; i < versionCount; i++) {
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index a380344..47be7e6 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -100,6 +100,8 @@
     public static final int FLAG_FREE_CACHE_V2 = IInstalld.FLAG_FREE_CACHE_V2;
     public static final int FLAG_FREE_CACHE_V2_DEFY_QUOTA = IInstalld.FLAG_FREE_CACHE_V2_DEFY_QUOTA;
     public static final int FLAG_FREE_CACHE_NOOP = IInstalld.FLAG_FREE_CACHE_NOOP;
+    public static final int FLAG_FREE_CACHE_DEFY_TARGET_FREE_BYTES =
+            IInstalld.FLAG_FREE_CACHE_DEFY_TARGET_FREE_BYTES;
 
     public static final int FLAG_USE_QUOTA = IInstalld.FLAG_USE_QUOTA;
     public static final int FLAG_FORCE = IInstalld.FLAG_FORCE;
diff --git a/services/core/java/com/android/server/pm/InstantAppRegistry.java b/services/core/java/com/android/server/pm/InstantAppRegistry.java
index f7d4dba..1de239e 100644
--- a/services/core/java/com/android/server/pm/InstantAppRegistry.java
+++ b/services/core/java/com/android/server/pm/InstantAppRegistry.java
@@ -59,6 +59,7 @@
 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
 import com.android.server.pm.permission.PermissionManagerServiceInternal;
 import com.android.server.pm.pkg.PackageStateInternal;
+import com.android.server.pm.pkg.PackageStateUtils;
 import com.android.server.pm.pkg.PackageUserStateInternal;
 import com.android.server.utils.Snappable;
 import com.android.server.utils.SnapshotCache;
@@ -854,7 +855,10 @@
                         } else if (lhsPs.getTransientState().getLatestPackageUseTimeInMills() <
                                 rhsPs.getTransientState().getLatestPackageUseTimeInMills()) {
                             return -1;
-                        } else if (lhsPs.getFirstInstallTime() > rhsPs.getFirstInstallTime()) {
+                        } else if (
+                                PackageStateUtils.getEarliestFirstInstallTime(lhsPs.getUserStates())
+                                > PackageStateUtils.getEarliestFirstInstallTime(
+                                        rhsPs.getUserStates())) {
                             return 1;
                         } else {
                             return -1;
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 6e6773f..ca87685 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -88,6 +88,7 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.content.PackageMonitor;
+import com.android.internal.infra.AndroidFuture;
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.CollectionUtils;
@@ -103,6 +104,7 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Objects;
+import java.util.concurrent.ExecutionException;
 
 /**
  * Service that manages requests and callbacks for launchers that support
@@ -728,9 +730,16 @@
                 return null;
             }
 
-            final Intent[] intents = mShortcutServiceInternal.createShortcutIntents(
-                    getCallingUserId(), callingPackage, packageName, shortcutId,
-                    user.getIdentifier(), injectBinderCallingPid(), injectBinderCallingUid());
+            final AndroidFuture<Intent[]> ret = new AndroidFuture<>();
+            Intent[] intents;
+            mShortcutServiceInternal.createShortcutIntentsAsync(getCallingUserId(),
+                    callingPackage, packageName, shortcutId, user.getIdentifier(),
+                    injectBinderCallingPid(), injectBinderCallingUid(), ret);
+            try {
+                intents = ret.get();
+            } catch (InterruptedException | ExecutionException e) {
+                return null;
+            }
             if (intents == null || intents.length == 0) {
                 return null;
             }
@@ -901,6 +910,40 @@
         }
 
         @Override
+        public void getShortcutsAsync(@NonNull final String callingPackage,
+                @NonNull final ShortcutQueryWrapper query, @NonNull final UserHandle targetUser,
+                @NonNull final AndroidFuture<List<ShortcutInfo>> cb) {
+            ensureShortcutPermission(callingPackage);
+            if (!canAccessProfile(targetUser.getIdentifier(), "Cannot get shortcuts")) {
+                cb.complete(Collections.EMPTY_LIST);
+                return;
+            }
+
+            final long changedSince = query.getChangedSince();
+            final String packageName = query.getPackage();
+            final List<String> shortcutIds = query.getShortcutIds();
+            final List<LocusId> locusIds = query.getLocusIds();
+            final ComponentName componentName = query.getActivity();
+            final int flags = query.getQueryFlags();
+            if (shortcutIds != null && packageName == null) {
+                throw new IllegalArgumentException(
+                        "To query by shortcut ID, package name must also be set");
+            }
+            if (locusIds != null && packageName == null) {
+                throw new IllegalArgumentException(
+                        "To query by locus ID, package name must also be set");
+            }
+            if ((query.getQueryFlags() & ShortcutQuery.FLAG_GET_PERSONS_DATA) != 0) {
+                ensureStrictAccessShortcutsPermission(callingPackage);
+            }
+
+            mShortcutServiceInternal.getShortcutsAsync(getCallingUserId(),
+                    callingPackage, changedSince, packageName, shortcutIds, locusIds,
+                    componentName, flags, targetUser.getIdentifier(),
+                    injectBinderCallingPid(), injectBinderCallingUid(), cb);
+        }
+
+        @Override
         public void registerShortcutChangeCallback(@NonNull final String callingPackage,
                 @NonNull final ShortcutQueryWrapper query,
                 @NonNull final IShortcutChangeCallback callback) {
@@ -991,8 +1034,14 @@
                 return null;
             }
 
-            return mShortcutServiceInternal.getShortcutIconFd(getCallingUserId(),
-                    callingPackage, packageName, id, targetUserId);
+            final AndroidFuture<ParcelFileDescriptor> ret = new AndroidFuture<>();
+            mShortcutServiceInternal.getShortcutIconFdAsync(getCallingUserId(),
+                    callingPackage, packageName, id, targetUserId, ret);
+            try {
+                return ret.get();
+            } catch (InterruptedException | ExecutionException e) {
+                throw new RuntimeException(e);
+            }
         }
 
         @Override
@@ -1003,8 +1052,14 @@
                 return null;
             }
 
-            return mShortcutServiceInternal.getShortcutIconUri(getCallingUserId(), callingPackage,
-                    packageName, shortcutId, userId);
+            final AndroidFuture<String> ret = new AndroidFuture<>();
+            mShortcutServiceInternal.getShortcutIconUriAsync(getCallingUserId(), callingPackage,
+                    packageName, shortcutId, userId, ret);
+            try {
+                return ret.get();
+            } catch (InterruptedException | ExecutionException e) {
+                throw new RuntimeException(e);
+            }
         }
 
         @Override
@@ -1037,9 +1092,16 @@
                 ensureShortcutPermission(callerUid, callerPid, callingPackage);
             }
 
-            final Intent[] intents = mShortcutServiceInternal.createShortcutIntents(
-                    callingUserId, callingPackage, packageName, shortcutId, targetUserId,
-                    callerPid, callerUid);
+            final AndroidFuture<Intent[]> ret = new AndroidFuture<>();
+            Intent[] intents;
+            mShortcutServiceInternal.createShortcutIntentsAsync(getCallingUserId(), callingPackage,
+                    packageName, shortcutId, targetUserId,
+                    injectBinderCallingPid(), injectBinderCallingUid(), ret);
+            try {
+                intents = ret.get();
+            } catch (InterruptedException | ExecutionException e) {
+                return false;
+            }
             if (intents == null || intents.length == 0) {
                 return false;
             }
@@ -1685,14 +1747,12 @@
                             continue;
                         }
                         final String[] filteredPackagesWithoutExtras =
-                                getFilteredPackageNames(packages, cookie);
-                        // If all packages are filtered, skip notifying listener.
-                        if (ArrayUtils.isEmpty(filteredPackagesWithoutExtras)) {
-                            continue;
-                        }
+                                getFilteredPackageNames(packagesNullExtras, cookie);
                         try {
-                            listener.onPackagesSuspended(user, filteredPackagesWithoutExtras,
-                                    /* launcherExtras= */ null);
+                            if (!ArrayUtils.isEmpty(filteredPackagesWithoutExtras)) {
+                                listener.onPackagesSuspended(user, filteredPackagesWithoutExtras,
+                                        /* launcherExtras= */ null);
+                            }
                             for (int idx = 0; idx < packagesWithExtras.size(); idx++) {
                                 Pair<String, Bundle> packageExtraPair = packagesWithExtras.get(idx);
                                 if (!isPackageVisibleToListener(packageExtraPair.first, cookie)) {
diff --git a/services/core/java/com/android/server/pm/MovePackageHelper.java b/services/core/java/com/android/server/pm/MovePackageHelper.java
index 19ebb5d..652a9ae 100644
--- a/services/core/java/com/android/server/pm/MovePackageHelper.java
+++ b/services/core/java/com/android/server/pm/MovePackageHelper.java
@@ -130,7 +130,7 @@
                         "Device admin cannot be moved");
             }
 
-            if (mPm.mFrozenPackages.contains(packageName)) {
+            if (mPm.mFrozenPackages.containsKey(packageName)) {
                 throw new PackageManagerException(MOVE_FAILED_OPERATION_PENDING,
                         "Failed to move already frozen package");
             }
@@ -188,6 +188,7 @@
             for (int userId : installedUserIds) {
                 if (StorageManager.isFileEncryptedNativeOrEmulated()
                         && !StorageManager.isUserKeyUnlocked(userId)) {
+                    freezer.close();
                     throw new PackageManagerException(MOVE_FAILED_LOCKED_USER,
                             "User " + userId + " must be unlocked");
                 }
@@ -230,6 +231,7 @@
         final IPackageInstallObserver2 installObserver = new IPackageInstallObserver2.Stub() {
             @Override
             public void onUserActionRequired(Intent intent) throws RemoteException {
+                freezer.close();
                 throw new IllegalStateException();
             }
 
diff --git a/services/core/java/com/android/server/pm/PackageFreezer.java b/services/core/java/com/android/server/pm/PackageFreezer.java
index ecc92b7..1e0a1f2 100644
--- a/services/core/java/com/android/server/pm/PackageFreezer.java
+++ b/services/core/java/com/android/server/pm/PackageFreezer.java
@@ -31,8 +31,6 @@
 final class PackageFreezer implements AutoCloseable {
     private final String mPackageName;
 
-    private final boolean mWeFroze;
-
     private final AtomicBoolean mClosed = new AtomicBoolean();
     private final CloseGuard mCloseGuard = CloseGuard.get();
 
@@ -48,7 +46,7 @@
     PackageFreezer(PackageManagerService pm) {
         mPm = pm;
         mPackageName = null;
-        mWeFroze = false;
+        mClosed.set(true);
         mCloseGuard.open("close");
     }
 
@@ -58,7 +56,9 @@
         mPackageName = packageName;
         final PackageSetting ps;
         synchronized (mPm.mLock) {
-            mWeFroze = mPm.mFrozenPackages.add(mPackageName);
+            final int refCounts = mPm.mFrozenPackages
+                    .getOrDefault(mPackageName, 0 /* defaultValue */) + 1;
+            mPm.mFrozenPackages.put(mPackageName, refCounts);
             ps = mPm.mSettings.getPackageLPr(mPackageName);
         }
         if (ps != null) {
@@ -82,7 +82,11 @@
         mCloseGuard.close();
         if (mClosed.compareAndSet(false, true)) {
             synchronized (mPm.mLock) {
-                if (mWeFroze) {
+                final int refCounts = mPm.mFrozenPackages
+                        .getOrDefault(mPackageName, 0 /* defaultValue */) - 1;
+                if (refCounts > 0) {
+                    mPm.mFrozenPackages.put(mPackageName, refCounts);
+                } else {
                     mPm.mFrozenPackages.remove(mPackageName);
                 }
             }
diff --git a/services/core/java/com/android/server/pm/PackageHandler.java b/services/core/java/com/android/server/pm/PackageHandler.java
index 217bc23..d1ea41a 100644
--- a/services/core/java/com/android/server/pm/PackageHandler.java
+++ b/services/core/java/com/android/server/pm/PackageHandler.java
@@ -388,7 +388,8 @@
             }
             case PRUNE_UNUSED_STATIC_SHARED_LIBRARIES: {
                 try {
-                    mPm.pruneUnusedStaticSharedLibraries(Long.MAX_VALUE,
+                    mPm.mInjector.getSharedLibrariesImpl().pruneUnusedStaticSharedLibraries(
+                            Long.MAX_VALUE,
                             Settings.Global.getLong(mPm.mContext.getContentResolver(),
                                     Settings.Global.UNUSED_STATIC_SHARED_LIB_MIN_CACHE_PERIOD,
                                     DEFAULT_UNUSED_STATIC_SHARED_LIB_MIN_CACHE_PERIOD));
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index f474044..cfcf199 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -404,7 +404,11 @@
                 if (age >= MAX_SESSION_AGE_ON_LOW_STORAGE_MILLIS) {
                     // Aggressively close old sessions because we are running low on storage
                     // Their staging dirs will be removed too
-                    session.abandon();
+                    PackageInstallerSession root = !session.hasParentSessionId()
+                            ? session : mSessions.get(session.getParentSessionId());
+                    if (!root.isDestroyed()) {
+                        root.abandon();
+                    }
                 } else {
                     // Session is new enough, so it deserves to be kept even on low storage
                     unclaimedStagingDirsOnVolume.remove(session.stageDir);
@@ -1623,7 +1627,7 @@
                     progress);
         }
 
-        public void onStagedSessionChanged(PackageInstallerSession session) {
+        public void onSessionChanged(PackageInstallerSession session) {
             session.markUpdated();
             mSettingsWriteRequest.schedule();
             if (mOkToSendBroadcasts && !session.isDestroyed()) {
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index a94985c..f45e54b 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -81,7 +81,7 @@
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageInstaller;
 import android.content.pm.PackageInstaller.SessionInfo;
-import android.content.pm.PackageInstaller.SessionInfo.StagedSessionErrorCode;
+import android.content.pm.PackageInstaller.SessionInfo.SessionErrorCode;
 import android.content.pm.PackageInstaller.SessionParams;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
@@ -151,7 +151,6 @@
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.Preconditions;
 import com.android.server.LocalServices;
-import com.android.server.SystemConfig;
 import com.android.server.pm.Installer.InstallerException;
 import com.android.server.pm.dex.DexManager;
 import com.android.server.pm.parsing.pkg.AndroidPackage;
@@ -229,8 +228,8 @@
     private static final String ATTR_IS_READY = "isReady";
     private static final String ATTR_IS_FAILED = "isFailed";
     private static final String ATTR_IS_APPLIED = "isApplied";
-    private static final String ATTR_STAGED_SESSION_ERROR_CODE = "errorCode";
-    private static final String ATTR_STAGED_SESSION_ERROR_MESSAGE = "errorMessage";
+    private static final String ATTR_SESSION_ERROR_CODE = "errorCode";
+    private static final String ATTR_SESSION_ERROR_MESSAGE = "errorMessage";
     private static final String ATTR_MODE = "mode";
     private static final String ATTR_INSTALL_FLAGS = "installFlags";
     private static final String ATTR_INSTALL_LOCATION = "installLocation";
@@ -454,22 +453,22 @@
     @GuardedBy("mLock")
     private ArrayMap<String, PerFileChecksum> mChecksums = new ArrayMap<>();
 
+    @GuardedBy("mLock")
+    private boolean mSessionApplied;
+    @GuardedBy("mLock")
+    private boolean mSessionReady;
+    @GuardedBy("mLock")
+    private boolean mSessionFailed;
+    @GuardedBy("mLock")
+    private int mSessionErrorCode = SessionInfo.STAGED_SESSION_NO_ERROR;
+    @GuardedBy("mLock")
+    private String mSessionErrorMessage;
+
     @Nullable
     final StagedSession mStagedSession;
 
     @VisibleForTesting
     public class StagedSession implements StagingManager.StagedSession {
-        @GuardedBy("mLock")
-        private boolean mSessionApplied;
-        @GuardedBy("mLock")
-        private boolean mSessionReady;
-        @GuardedBy("mLock")
-        private boolean mSessionFailed;
-        @GuardedBy("mLock")
-        private int mSessionErrorCode = SessionInfo.STAGED_SESSION_NO_ERROR;
-        @GuardedBy("mLock")
-        private String mSessionErrorMessage;
-
         /**
          * The callback to run when pre-reboot verification has ended. Used by {@link #abandon()}
          * to delay session clean-up until it is safe to do so.
@@ -478,15 +477,6 @@
         @Nullable
         private Runnable mPendingAbandonCallback;
 
-        StagedSession(boolean isReady, boolean isApplied, boolean isFailed, int errorCode,
-                String errorMessage) {
-            mSessionReady = isReady;
-            mSessionApplied = isApplied;
-            mSessionFailed = isFailed;
-            mSessionErrorCode = errorCode;
-            mSessionErrorMessage = errorMessage != null ? errorMessage : "";
-        }
-
         @Override
         public List<StagingManager.StagedSession> getChildSessions() {
             if (!params.isMultiPackage) {
@@ -534,52 +524,17 @@
 
         @Override
         public void setSessionReady() {
-            synchronized (mLock) {
-                // Do not allow destroyed/failed staged session to change state
-                if (mDestroyed || mSessionFailed) return;
-                mSessionReady = true;
-                mSessionApplied = false;
-                mSessionFailed = false;
-                mSessionErrorCode = SessionInfo.STAGED_SESSION_NO_ERROR;
-                mSessionErrorMessage = "";
-            }
-            mCallback.onStagedSessionChanged(PackageInstallerSession.this);
+            PackageInstallerSession.this.setSessionReady();
         }
 
         @Override
         public void setSessionFailed(int errorCode, String errorMessage) {
-            List<PackageInstallerSession> childSessions;
-            synchronized (mLock) {
-                // Do not allow destroyed/failed staged session to change state
-                if (mDestroyed || mSessionFailed) return;
-                mSessionReady = false;
-                mSessionApplied = false;
-                mSessionFailed = true;
-                mSessionErrorCode = errorCode;
-                mSessionErrorMessage = errorMessage;
-                Slog.d(TAG, "Marking session " + sessionId + " as failed: " + errorMessage);
-                childSessions = getChildSessionsLocked();
-            }
-            destroy();
-            mCallback.onStagedSessionChanged(PackageInstallerSession.this);
+            PackageInstallerSession.this.setSessionFailed(errorCode, errorMessage);
         }
 
         @Override
         public void setSessionApplied() {
-            List<PackageInstallerSession> childSessions;
-            synchronized (mLock) {
-                // Do not allow destroyed/failed staged session to change state
-                if (mDestroyed || mSessionFailed) return;
-                mSessionReady = false;
-                mSessionApplied = true;
-                mSessionFailed = false;
-                mSessionErrorCode = SessionInfo.STAGED_SESSION_NO_ERROR;
-                mSessionErrorMessage = "";
-                Slog.d(TAG, "Marking session " + sessionId + " as applied");
-                childSessions = getChildSessionsLocked();
-            }
-            destroy();
-            mCallback.onStagedSessionChanged(PackageInstallerSession.this);
+            PackageInstallerSession.this.setSessionApplied();
         }
 
         @Override
@@ -656,35 +611,17 @@
 
         @Override
         public boolean isSessionReady() {
-            synchronized (mLock) {
-                return mSessionReady;
-            }
+            return PackageInstallerSession.this.isSessionReady();
         }
 
         @Override
         public boolean isSessionApplied() {
-            synchronized (mLock) {
-                return mSessionApplied;
-            }
+            return PackageInstallerSession.this.isSessionApplied();
         }
 
         @Override
         public boolean isSessionFailed() {
-            synchronized (mLock) {
-                return mSessionFailed;
-            }
-        }
-
-        @StagedSessionErrorCode int getSessionErrorCode() {
-            synchronized (mLock) {
-                return mSessionErrorCode;
-            }
-        }
-
-        String getSessionErrorMessage() {
-            synchronized (mLock) {
-                return mSessionErrorMessage;
-            }
+            return PackageInstallerSession.this.isSessionFailed();
         }
 
         @Override
@@ -714,7 +651,7 @@
                 if (mStageDirInUse) {
                     // Pre-reboot verification is ongoing, not safe to clean up the session yet.
                     mPendingAbandonCallback = r;
-                    mCallback.onStagedSessionChanged(PackageInstallerSession.this);
+                    mCallback.onSessionChanged(PackageInstallerSession.this);
                     return;
                 }
             }
@@ -1015,8 +952,8 @@
             ArrayMap<String, PerFileChecksum> checksums,
             boolean prepared, boolean committed, boolean destroyed, boolean sealed,
             @Nullable int[] childSessionIds, int parentSessionId, boolean isReady,
-            boolean isFailed, boolean isApplied, int stagedSessionErrorCode,
-            String stagedSessionErrorMessage) {
+            boolean isFailed, boolean isApplied, int sessionErrorCode,
+            String sessionErrorMessage) {
         mCallback = callback;
         mContext = context;
         mPm = pm;
@@ -1071,8 +1008,13 @@
         mPrepared = prepared;
         mCommitted.set(committed);
         mDestroyed = destroyed;
-        mStagedSession = params.isStaged ? new StagedSession(isReady, isApplied, isFailed,
-                stagedSessionErrorCode, stagedSessionErrorMessage) : null;
+        mSessionReady = isReady;
+        mSessionApplied = isApplied;
+        mSessionFailed = isFailed;
+        mSessionErrorCode = sessionErrorCode;
+        mSessionErrorMessage =
+                sessionErrorMessage != null ? sessionErrorMessage : "";
+        mStagedSession = params.isStaged ? new StagedSession() : null;
 
         if (isDataLoaderInstallation()) {
             if (isApexSession()) {
@@ -1173,11 +1115,10 @@
             info.rollbackDataPolicy = params.rollbackDataPolicy;
             info.parentSessionId = mParentSessionId;
             info.childSessionIds = getChildSessionIdsLocked();
-            info.isStagedSessionApplied = isStagedSessionApplied();
-            info.isStagedSessionReady = isStagedSessionReady();
-            info.isStagedSessionFailed = isStagedSessionFailed();
-            info.setStagedSessionErrorCode(getStagedSessionErrorCode(),
-                    getStagedSessionErrorMessage());
+            info.isSessionApplied = mSessionApplied;
+            info.isSessionReady = mSessionReady;
+            info.isSessionFailed = mSessionFailed;
+            info.setSessionErrorCode(mSessionErrorCode, mSessionErrorMessage);
             info.createdMillis = createdMillis;
             info.updatedMillis = updatedMillis;
             info.requireUserAction = params.requireUserAction;
@@ -2229,7 +2170,7 @@
                 final PackageInstallerSession root = hasParentSessionId()
                         ? allSessions.get(getParentSessionId())
                         : this;
-                if (root != null) {
+                if (root != null && !root.isStagedAndInTerminalState()) {
                     if (isApexSession()) {
                         validateApexInstallLocked();
                     } else {
@@ -2357,28 +2298,6 @@
             return;
         }
 
-
-        // Check if APEX update is allowed. We do this check in handleInstall, since this is one of
-        // the places that:
-        //   * Shared between staged and non-staged APEX update flows.
-        //   * Only is called after boot completes.
-        // The later is important, since isApexUpdateAllowed check depends on the
-        // ModuleInfoProvider, which is only populated after device has booted.
-        if (isApexSession()) {
-            boolean checkApexUpdateAllowed =
-                    (params.installFlags & PackageManager.INSTALL_DISABLE_ALLOWED_APEX_UPDATE_CHECK)
-                        == 0;
-            synchronized (mLock) {
-                if (checkApexUpdateAllowed && !isApexUpdateAllowed(mPackageName,
-                          mInstallSource.installerPackageName)) {
-                    onSessionValidationFailure(PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
-                            "Update of APEX package " + mPackageName + " is not allowed for "
-                                    + mInstallSource.installerPackageName);
-                    return;
-                }
-            }
-        }
-
         if (params.isStaged) {
             // TODO(b/136257624): CTS test fails if we don't send session finished broadcast, even
             //  though ideally, we just need to send session committed broadcast.
@@ -2825,25 +2744,6 @@
         return sessionContains((s) -> !s.isApexSession());
     }
 
-    private boolean isApexUpdateAllowed(String apexPackageName, String installerPackageName) {
-        if (mPm.getModuleInfo(apexPackageName, 0) != null) {
-            final String modulesInstaller =
-                    SystemConfig.getInstance().getModulesInstallerPackageName();
-            if (modulesInstaller == null) {
-                Slog.w(TAG, "No modules installer defined");
-                return false;
-            }
-            return modulesInstaller.equals(installerPackageName);
-        }
-        final String vendorApexInstaller =
-                SystemConfig.getInstance().getAllowedVendorApexes().get(apexPackageName);
-        if (vendorApexInstaller == null) {
-            Slog.w(TAG, apexPackageName + " is not allowed to be updated");
-            return false;
-        }
-        return vendorApexInstaller.equals(installerPackageName);
-    }
-
     /**
      * Validate apex install.
      * <p>
@@ -4261,30 +4161,83 @@
         }
     }
 
-    /** {@hide} */
-    boolean isStagedSessionReady() {
-        return params.isStaged && mStagedSession.isSessionReady();
+    private void setSessionReady() {
+        synchronized (mLock) {
+            // Do not allow destroyed/failed session to change state
+            if (mDestroyed || mSessionFailed) return;
+            mSessionReady = true;
+            mSessionApplied = false;
+            mSessionFailed = false;
+            mSessionErrorCode = SessionInfo.STAGED_SESSION_NO_ERROR;
+            mSessionErrorMessage = "";
+        }
+        mCallback.onSessionChanged(this);
+    }
+
+    private void setSessionFailed(int errorCode, String errorMessage) {
+        synchronized (mLock) {
+            // Do not allow destroyed/failed session to change state
+            if (mDestroyed || mSessionFailed) return;
+            mSessionReady = false;
+            mSessionApplied = false;
+            mSessionFailed = true;
+            mSessionErrorCode = errorCode;
+            mSessionErrorMessage = errorMessage;
+            Slog.d(TAG, "Marking session " + sessionId + " as failed: " + errorMessage);
+        }
+        destroy();
+        mCallback.onSessionChanged(this);
+    }
+
+    private void setSessionApplied() {
+        synchronized (mLock) {
+            // Do not allow destroyed/failed session to change state
+            if (mDestroyed || mSessionFailed) return;
+            mSessionReady = false;
+            mSessionApplied = true;
+            mSessionFailed = false;
+            mSessionErrorCode = SessionInfo.STAGED_SESSION_NO_ERROR;
+            mSessionErrorMessage = "";
+            Slog.d(TAG, "Marking session " + sessionId + " as applied");
+        }
+        destroy();
+        mCallback.onSessionChanged(this);
     }
 
     /** {@hide} */
-    boolean isStagedSessionApplied() {
-        return params.isStaged && mStagedSession.isSessionApplied();
+    boolean isSessionReady() {
+        synchronized (mLock) {
+            return mSessionReady;
+        }
     }
 
     /** {@hide} */
-    boolean isStagedSessionFailed() {
-        return params.isStaged && mStagedSession.isSessionFailed();
+    boolean isSessionApplied() {
+        synchronized (mLock) {
+            return mSessionApplied;
+        }
     }
 
     /** {@hide} */
-    @StagedSessionErrorCode int getStagedSessionErrorCode() {
-        return params.isStaged ? mStagedSession.getSessionErrorCode()
-                : SessionInfo.STAGED_SESSION_NO_ERROR;
+    boolean isSessionFailed() {
+        synchronized (mLock) {
+            return mSessionFailed;
+        }
     }
 
     /** {@hide} */
-    String getStagedSessionErrorMessage() {
-        return params.isStaged ? mStagedSession.getSessionErrorMessage() : "";
+    @SessionErrorCode
+    int getSessionErrorCode() {
+        synchronized (mLock) {
+            return mSessionErrorCode;
+        }
+    }
+
+    /** {@hide} */
+    String getSessionErrorMessage() {
+        synchronized (mLock) {
+            return mSessionErrorMessage;
+        }
     }
 
     /**
@@ -4386,11 +4339,11 @@
         pw.printPair("params.isStaged", params.isStaged);
         pw.printPair("mParentSessionId", mParentSessionId);
         pw.printPair("mChildSessionIds", getChildSessionIdsLocked());
-        pw.printPair("mStagedSessionApplied", isStagedSessionApplied());
-        pw.printPair("mStagedSessionFailed", isStagedSessionFailed());
-        pw.printPair("mStagedSessionReady", isStagedSessionReady());
-        pw.printPair("mStagedSessionErrorCode", getStagedSessionErrorCode());
-        pw.printPair("mStagedSessionErrorMessage", getStagedSessionErrorMessage());
+        pw.printPair("mSessionApplied", mSessionApplied);
+        pw.printPair("mSessionFailed", mSessionFailed);
+        pw.printPair("mSessionReady", mSessionReady);
+        pw.printPair("mSessionErrorCode", mSessionErrorCode);
+        pw.printPair("mSessionErrorMessage", mSessionErrorMessage);
         pw.println();
 
         pw.decreaseIndent();
@@ -4556,12 +4509,11 @@
 
             writeBooleanAttribute(out, ATTR_MULTI_PACKAGE, params.isMultiPackage);
             writeBooleanAttribute(out, ATTR_STAGED_SESSION, params.isStaged);
-            writeBooleanAttribute(out, ATTR_IS_READY, isStagedSessionReady());
-            writeBooleanAttribute(out, ATTR_IS_FAILED, isStagedSessionFailed());
-            writeBooleanAttribute(out, ATTR_IS_APPLIED, isStagedSessionApplied());
-            out.attributeInt(null, ATTR_STAGED_SESSION_ERROR_CODE, getStagedSessionErrorCode());
-            writeStringAttribute(out, ATTR_STAGED_SESSION_ERROR_MESSAGE,
-                    getStagedSessionErrorMessage());
+            writeBooleanAttribute(out, ATTR_IS_READY, mSessionReady);
+            writeBooleanAttribute(out, ATTR_IS_FAILED, mSessionFailed);
+            writeBooleanAttribute(out, ATTR_IS_APPLIED, mSessionApplied);
+            out.attributeInt(null, ATTR_SESSION_ERROR_CODE, mSessionErrorCode);
+            writeStringAttribute(out, ATTR_SESSION_ERROR_MESSAGE, mSessionErrorMessage);
             // TODO(patb,109941548): avoid writing to xml and instead infer / validate this after
             //                       we've read all sessions.
             out.attributeInt(null, ATTR_PARENT_SESSION_ID, mParentSessionId);
@@ -4752,10 +4704,9 @@
         final boolean isReady = in.getAttributeBoolean(null, ATTR_IS_READY, false);
         final boolean isFailed = in.getAttributeBoolean(null, ATTR_IS_FAILED, false);
         final boolean isApplied = in.getAttributeBoolean(null, ATTR_IS_APPLIED, false);
-        final int stagedSessionErrorCode = in.getAttributeInt(null, ATTR_STAGED_SESSION_ERROR_CODE,
+        final int sessionErrorCode = in.getAttributeInt(null, ATTR_SESSION_ERROR_CODE,
                 SessionInfo.STAGED_SESSION_NO_ERROR);
-        final String stagedSessionErrorMessage = readStringAttribute(in,
-                ATTR_STAGED_SESSION_ERROR_MESSAGE);
+        final String sessionErrorMessage = readStringAttribute(in, ATTR_SESSION_ERROR_MESSAGE);
 
         if (!isStagedSessionStateValid(isReady, isApplied, isFailed)) {
             throw new IllegalArgumentException("Can't restore staged session with invalid state.");
@@ -4869,6 +4820,6 @@
                 installerUid, installSource, params, createdMillis, committedMillis, stageDir,
                 stageCid, fileArray, checksumsMap, prepared, committed, destroyed, sealed,
                 childSessionIdsArray, parentSessionId, isReady, isFailed, isApplied,
-                stagedSessionErrorCode, stagedSessionErrorMessage);
+                sessionErrorCode, sessionErrorMessage);
     }
 }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 6f8703b..248944e 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -239,6 +239,9 @@
 import com.android.server.pm.pkg.PackageUserState;
 import com.android.server.pm.pkg.PackageUserStateInternal;
 import com.android.server.pm.pkg.SuspendParams;
+import com.android.server.pm.pkg.mutate.PackageStateMutator;
+import com.android.server.pm.pkg.mutate.PackageStateWrite;
+import com.android.server.pm.pkg.mutate.PackageUserStateWrite;
 import com.android.server.pm.verify.domain.DomainVerificationManagerInternal;
 import com.android.server.pm.verify.domain.DomainVerificationService;
 import com.android.server.pm.verify.domain.proxy.DomainVerificationProxy;
@@ -249,8 +252,6 @@
 import com.android.server.utils.Watchable;
 import com.android.server.utils.Watched;
 import com.android.server.utils.WatchedArrayMap;
-import com.android.server.utils.WatchedArraySet;
-import com.android.server.utils.WatchedLongSparseArray;
 import com.android.server.utils.WatchedSparseBooleanArray;
 import com.android.server.utils.WatchedSparseIntArray;
 import com.android.server.utils.Watcher;
@@ -280,7 +281,6 @@
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Iterator;
-import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
@@ -290,7 +290,6 @@
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
-import java.util.function.BiConsumer;
 import java.util.function.Consumer;
 import java.util.function.Function;
 import java.util.function.Predicate;
@@ -598,6 +597,16 @@
     // the suffix "Locked". Some methods may use the legacy suffix "LP"
     final PackageManagerTracedLock mLock;
 
+    // Lock alias for doing package state mutation
+    private final PackageManagerTracedLock mPackageStateWriteLock;
+
+    // Lock alias to track syncing a consistent Computer
+    private final PackageManagerTracedLock mLiveComputerSyncLock;
+
+    private final PackageStateMutator mPackageStateMutator = new PackageStateMutator(
+            this::getPackageSettingForMutation,
+            this::getDisabledPackageSettingForMutation);
+
     // Keys are String (package name), values are Package.
     @Watched
     @GuardedBy("mLock")
@@ -646,15 +655,16 @@
     final Settings mSettings;
 
     /**
-     * Set of package names that are currently "frozen", which means active
-     * surgery is being done on the code/data for that package. The platform
-     * will refuse to launch frozen packages to avoid race conditions.
+     * Map of package names to frozen counts that are currently "frozen",
+     * which means active surgery is being done on the code/data for that
+     * package. The platform will refuse to launch frozen packages to avoid
+     * race conditions.
      *
      * @see PackageFreezer
      */
     @GuardedBy("mLock")
-    final WatchedArraySet<String> mFrozenPackages = new WatchedArraySet<>();
-    private final SnapshotCache<WatchedArraySet<String>> mFrozenPackagesSnapshot =
+    final WatchedArrayMap<String, Integer> mFrozenPackages = new WatchedArrayMap<>();
+    private final SnapshotCache<WatchedArrayMap<String, Integer>> mFrozenPackagesSnapshot =
             new SnapshotCache.Auto(mFrozenPackages, mFrozenPackages,
                     "PackageManagerService.mFrozenPackages");
 
@@ -757,19 +767,7 @@
 
     // Currently known shared libraries.
     @Watched
-    final WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>>
-            mSharedLibraries = new WatchedArrayMap<>();
-    private final SnapshotCache<WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>>>
-            mSharedLibrariesSnapshot =
-            new SnapshotCache.Auto<>(mSharedLibraries, mSharedLibraries,
-                                     "PackageManagerService.mSharedLibraries");
-    @Watched
-    final WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>>
-            mStaticLibsByDeclaringPackage = new WatchedArrayMap<>();
-    private final SnapshotCache<WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>>>
-            mStaticLibsByDeclaringPackageSnapshot =
-            new SnapshotCache.Auto<>(mStaticLibsByDeclaringPackage, mStaticLibsByDeclaringPackage,
-                                     "PackageManagerService.mStaticLibsByDeclaringPackage");
+    private final SharedLibrariesImpl mSharedLibraries;
 
     // Mapping from instrumentation class names to info about them.
     @Watched
@@ -1002,8 +1000,6 @@
         public final Settings settings;
         public final WatchedSparseIntArray isolatedOwners;
         public final WatchedArrayMap<String, AndroidPackage> packages;
-        public final WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>> sharedLibs;
-        public final WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>> staticLibs;
         public final WatchedArrayMap<ComponentName, ParsedInstrumentation> instrumentation;
         public final WatchedSparseBooleanArray webInstantAppsDisabled;
         public final ComponentName resolveComponentName;
@@ -1016,15 +1012,14 @@
         public final AppsFilter appsFilter;
         public final ComponentResolver componentResolver;
         public final PackageManagerService service;
-        public final WatchedArraySet<String> frozenPackages;
+        public final WatchedArrayMap<String, Integer> frozenPackages;
+        public final SharedLibrariesRead sharedLibraries;
 
         Snapshot(int type) {
             if (type == Snapshot.SNAPPED) {
                 settings = mSettings.snapshot();
                 isolatedOwners = mIsolatedOwnersSnapshot.snapshot();
                 packages = mPackagesSnapshot.snapshot();
-                sharedLibs = mSharedLibrariesSnapshot.snapshot();
-                staticLibs = mStaticLibsByDeclaringPackageSnapshot.snapshot();
                 instrumentation = mInstrumentationSnapshot.snapshot();
                 resolveComponentName = mResolveComponentName.clone();
                 resolveActivity = new ActivityInfo(mResolveActivity);
@@ -1043,12 +1038,11 @@
                 appsFilter = mAppsFilter.snapshot();
                 componentResolver = mComponentResolver.snapshot();
                 frozenPackages = mFrozenPackagesSnapshot.snapshot();
+                sharedLibraries = mSharedLibraries.snapshot();
             } else if (type == Snapshot.LIVE) {
                 settings = mSettings;
                 isolatedOwners = mIsolatedOwners;
                 packages = mPackages;
-                sharedLibs = mSharedLibraries;
-                staticLibs = mStaticLibsByDeclaringPackage;
                 instrumentation = mInstrumentation;
                 resolveComponentName = mResolveComponentName;
                 resolveActivity = mResolveActivity;
@@ -1061,6 +1055,7 @@
                 appsFilter = mAppsFilter;
                 componentResolver = mComponentResolver;
                 frozenPackages = mFrozenPackages;
+                sharedLibraries = mSharedLibraries;
             } else {
                 throw new IllegalArgumentException();
             }
@@ -1522,7 +1517,8 @@
                 context::getSystemService,
                 (i, pm) -> new BackgroundDexOptService(i.getContext(), i.getDexManager(), pm),
                 (i, pm) -> IBackupManager.Stub.asInterface(ServiceManager.getService(
-                        Context.BACKUP_SERVICE)));
+                        Context.BACKUP_SERVICE)),
+                (i, pm) -> new SharedLibrariesImpl(pm, i));
 
         if (Build.VERSION.SDK_INT <= 0) {
             Slog.w(TAG, "**** ro.build.version.sdk not set!");
@@ -1594,7 +1590,6 @@
     private void registerObserver() {
         mPackages.registerObserver(mWatcher);
         mSharedLibraries.registerObserver(mWatcher);
-        mStaticLibsByDeclaringPackage.registerObserver(mWatcher);
         mInstrumentation.registerObserver(mWatcher);
         mWebInstantAppsDisabled.registerObserver(mWatcher);
         mAppsFilter.registerObserver(mWatcher);
@@ -1626,11 +1621,14 @@
         mInstaller = injector.getInstaller();
         mInstallLock = injector.getInstallLock();
         mLock = injector.getLock();
+        mPackageStateWriteLock = mLock;
+        mLiveComputerSyncLock = mLock;
         mPermissionManager = injector.getPermissionManagerServiceInternal();
         mSettings = injector.getSettings();
         mUserManager = injector.getUserManagerService();
         mDomainVerificationManager = injector.getDomainVerificationManagerInternal();
         mHandler = injector.getHandler();
+        mSharedLibraries = injector.getSharedLibrariesImpl();
 
         mApexManager = testParams.apexManager;
         mArtManagerService = testParams.artManagerService;
@@ -1708,6 +1706,7 @@
         mPreferredActivityHelper = testParams.preferredActivityHelper;
         mResolveIntentHelper = testParams.resolveIntentHelper;
         mDexOptHelper = testParams.dexOptHelper;
+        mSharedLibraries.setDeletePackageHelper(mDeletePackageHelper);
 
         invalidatePackageInfoCache();
     }
@@ -1729,6 +1728,8 @@
 
         mInjector.bootstrap(this);
         mLock = injector.getLock();
+        mPackageStateWriteLock = mLock;
+        mLiveComputerSyncLock = mLock;
         mInstallLock = injector.getInstallLock();
         LockGuard.installLock(mLock, LockGuard.INDEX_PACKAGES);
         EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,
@@ -1817,6 +1818,7 @@
         mArtManagerService = injector.getArtManagerService();
         mMoveCallbacks = new MovePackageHelper.MoveCallbacks(FgThread.get().getLooper());
         mViewCompiler = injector.getViewCompiler();
+        mSharedLibraries = mInjector.getSharedLibrariesImpl();
 
         mContext.getSystemService(DisplayManager.class)
                 .getDisplay(Display.DEFAULT_DISPLAY).getMetrics(mMetrics);
@@ -1846,6 +1848,7 @@
         mInitAndSystemPackageHelper = new InitAndSystemPackageHelper(this);
         mDeletePackageHelper = new DeletePackageHelper(this, mRemovePackageHelper,
                 mAppDataHelper);
+        mSharedLibraries.setDeletePackageHelper(mDeletePackageHelper);
         mPreferredActivityHelper = new PreferredActivityHelper(this);
         mResolveIntentHelper = new ResolveIntentHelper(this, mPreferredActivityHelper);
         mDexOptHelper = new DexOptHelper(this);
@@ -1877,7 +1880,7 @@
                     = systemConfig.getSharedLibraries();
             final int builtInLibCount = libConfig.size();
             for (int i = 0; i < builtInLibCount; i++) {
-                addBuiltInSharedLibraryLocked(libConfig.valueAt(i));
+                mSharedLibraries.addBuiltInSharedLibraryLPw(libConfig.valueAt(i));
             }
 
             // Now that we have added all the libraries, iterate again to add dependency
@@ -1996,7 +1999,8 @@
 
             // Now that we know all of the shared libraries, update all clients to have
             // the correct library paths.
-            updateAllSharedLibrariesLocked(null, null, Collections.unmodifiableMap(mPackages));
+            mSharedLibraries.updateAllSharedLibrariesLPw(
+                    null, null, Collections.unmodifiableMap(mPackages));
 
             for (SharedUserSetting setting : mSettings.getAllSharedUsersLPw()) {
                 // NOTE: We ignore potential failures here during a system scan (like
@@ -2780,6 +2784,23 @@
     }
 
     /**
+     * Blocking call to clear all cached app data above quota.
+     */
+    public void freeAllAppCacheAboveQuota(String volumeUuid) throws IOException {
+        synchronized (mInstallLock) {
+            // To avoid refactoring Installer.freeCache() and InstalldNativeService.freeCache(),
+            // Long.MAX_VALUE is passed as an argument which is used in neither of two methods
+            // when FLAG_FREE_CACHE_DEFY_TARGET_FREE_BYTES is set
+            try {
+                mInstaller.freeCache(volumeUuid, Long.MAX_VALUE, Installer.FLAG_FREE_CACHE_V2
+                        | Installer.FLAG_FREE_CACHE_DEFY_TARGET_FREE_BYTES);
+            } catch (InstallerException ignored) {
+            }
+        }
+        return;
+    }
+
+    /**
      * Blocking call to clear various types of cached data across the system
      * until the requested bytes are available.
      */
@@ -2818,7 +2839,7 @@
             if (file.getUsableSpace() >= bytes) return;
 
             // 5. Consider shared libraries with refcount=0 and age>min cache period
-            if (internalVolume && pruneUnusedStaticSharedLibraries(bytes,
+            if (internalVolume && mSharedLibraries.pruneUnusedStaticSharedLibraries(bytes,
                     android.provider.Settings.Global.getLong(mContext.getContentResolver(),
                             Global.UNUSED_STATIC_SHARED_LIB_MIN_CACHE_PERIOD,
                             FREE_STORAGE_UNUSED_STATIC_SHARED_LIB_MIN_CACHE_PERIOD))) {
@@ -2880,85 +2901,6 @@
         throw new IOException("Failed to free " + bytes + " on storage device at " + file);
     }
 
-    private PackageSetting getLibraryPackage(SharedLibraryInfo libInfo) {
-        final VersionedPackage declaringPackage = libInfo.getDeclaringPackage();
-        if (libInfo.isStatic()) {
-            // Resolve the package name - we use synthetic package names internally
-            final String internalPackageName = resolveInternalPackageNameLPr(
-                    declaringPackage.getPackageName(),
-                    declaringPackage.getLongVersionCode());
-            return mSettings.getPackageLPr(internalPackageName);
-        }
-        if (libInfo.isSdk()) {
-            return mSettings.getPackageLPr(declaringPackage.getPackageName());
-        }
-        return null;
-    }
-
-    boolean pruneUnusedStaticSharedLibraries(long neededSpace, long maxCachePeriod)
-            throws IOException {
-        final StorageManager storage = mInjector.getSystemService(StorageManager.class);
-        final File volume = storage.findPathForUuid(StorageManager.UUID_PRIVATE_INTERNAL);
-
-        List<VersionedPackage> packagesToDelete = null;
-        final long now = System.currentTimeMillis();
-
-        // Important: We skip shared libs used for some user since
-        // in such a case we need to keep the APK on the device. The check for
-        // a lib being used for any user is performed by the uninstall call.
-        synchronized (mLock) {
-            final int libCount = mSharedLibraries.size();
-            for (int i = 0; i < libCount; i++) {
-                final WatchedLongSparseArray<SharedLibraryInfo> versionedLib
-                        = mSharedLibraries.valueAt(i);
-                if (versionedLib == null) {
-                    continue;
-                }
-                final int versionCount = versionedLib.size();
-                for (int j = 0; j < versionCount; j++) {
-                    SharedLibraryInfo libInfo = versionedLib.valueAt(j);
-                    final PackageSetting ps = getLibraryPackage(libInfo);
-                    if (ps == null) {
-                        continue;
-                    }
-                    // Skip unused libs cached less than the min period to prevent pruning a lib
-                    // needed by a subsequently installed package.
-                    if (now - ps.getLastUpdateTime() < maxCachePeriod) {
-                        continue;
-                    }
-
-                    if (ps.getPkg().isSystem()) {
-                        continue;
-                    }
-
-                    if (packagesToDelete == null) {
-                        packagesToDelete = new ArrayList<>();
-                    }
-                    packagesToDelete.add(new VersionedPackage(ps.getPkg().getPackageName(),
-                            libInfo.getDeclaringPackage().getLongVersionCode()));
-                }
-            }
-        }
-
-        if (packagesToDelete != null) {
-            final int packageCount = packagesToDelete.size();
-            for (int i = 0; i < packageCount; i++) {
-                final VersionedPackage pkgToDelete = packagesToDelete.get(i);
-                // Delete the package synchronously (will fail of the lib used for any user).
-                if (mDeletePackageHelper.deletePackageX(pkgToDelete.getPackageName(),
-                        pkgToDelete.getLongVersionCode(), UserHandle.USER_SYSTEM,
-                        PackageManager.DELETE_ALL_USERS,
-                        true /*removedBySystem*/) == PackageManager.DELETE_SUCCEEDED) {
-                    if (volume.getUsableSpace() >= neededSpace) {
-                        return true;
-                    }
-                }
-            }
-        }
-
-        return false;
-    }
-
     /**
      * Update given flags when being used to request {@link PackageInfo}.
      */
@@ -3944,40 +3886,6 @@
         return mComputer.getSharedLibraryInfo(name, version);
     }
 
-    SharedLibraryInfo getLatestSharedLibraVersionLPr(AndroidPackage pkg) {
-        WatchedLongSparseArray<SharedLibraryInfo> versionedLib = mSharedLibraries.get(
-                pkg.getStaticSharedLibName());
-        if (versionedLib == null) {
-            return null;
-        }
-        long previousLibVersion = -1;
-        final int versionCount = versionedLib.size();
-        for (int i = 0; i < versionCount; i++) {
-            final long libVersion = versionedLib.keyAt(i);
-            if (libVersion < pkg.getStaticSharedLibVersion()) {
-                previousLibVersion = Math.max(previousLibVersion, libVersion);
-            }
-        }
-        if (previousLibVersion >= 0) {
-            return versionedLib.get(previousLibVersion);
-        }
-        return null;
-    }
-
-    @Nullable
-    PackageSetting getSharedLibLatestVersionSetting(@NonNull ScanResult scanResult) {
-        PackageSetting sharedLibPackage = null;
-        synchronized (mLock) {
-            final SharedLibraryInfo latestSharedLibraVersionLPr =
-                    getLatestSharedLibraVersionLPr(scanResult.mRequest.mParsedPackage);
-            if (latestSharedLibraVersionLPr != null) {
-                sharedLibPackage = mSettings.getPackageLPr(
-                        latestSharedLibraVersionLPr.getPackageName());
-            }
-        }
-        return sharedLibPackage;
-    }
-
     public void shutdown() {
         mCompilerStats.writeNow();
         mDexManager.writePackageDexUsageNow();
@@ -4032,253 +3940,6 @@
         return (userId == UserHandle.USER_ALL) ? mUserManager.getUserIds() : new int[] { userId };
     }
 
-    @GuardedBy("mLock")
-    private void applyDefiningSharedLibraryUpdateLocked(
-            AndroidPackage pkg, SharedLibraryInfo libInfo,
-            BiConsumer<SharedLibraryInfo, SharedLibraryInfo> action) {
-        // Note that libraries defined by this package may be null if:
-        // - Package manager was unable to create the shared library. The package still
-        //   gets installed, but the shared library does not get created.
-        // Or:
-        // - Package manager is in a state where package isn't scanned yet. This will
-        //   get called again after scanning to fix the dependencies.
-        if (AndroidPackageUtils.isLibrary(pkg)) {
-            if (pkg.getSdkLibName() != null) {
-                SharedLibraryInfo definedLibrary = getSharedLibraryInfo(
-                        pkg.getSdkLibName(), pkg.getSdkLibVersionMajor());
-                if (definedLibrary != null) {
-                    action.accept(definedLibrary, libInfo);
-                }
-            } else if (pkg.getStaticSharedLibName() != null) {
-                SharedLibraryInfo definedLibrary = getSharedLibraryInfo(
-                        pkg.getStaticSharedLibName(), pkg.getStaticSharedLibVersion());
-                if (definedLibrary != null) {
-                    action.accept(definedLibrary, libInfo);
-                }
-            } else {
-                for (String libraryName : pkg.getLibraryNames()) {
-                    SharedLibraryInfo definedLibrary = getSharedLibraryInfo(
-                            libraryName, SharedLibraryInfo.VERSION_UNDEFINED);
-                    if (definedLibrary != null) {
-                        action.accept(definedLibrary, libInfo);
-                    }
-                }
-            }
-        }
-    }
-
-    @GuardedBy("mLock")
-    private void addSharedLibraryLPr(AndroidPackage pkg, Set<String> usesLibraryFiles,
-            SharedLibraryInfo libInfo, @Nullable AndroidPackage changingLib,
-            @Nullable PackageSetting changingLibSetting) {
-        if (libInfo.getPath() != null) {
-            usesLibraryFiles.add(libInfo.getPath());
-            return;
-        }
-        AndroidPackage pkgForCodePaths = mPackages.get(libInfo.getPackageName());
-        PackageSetting pkgSetting = mSettings.getPackageLPr(libInfo.getPackageName());
-        if (changingLib != null && changingLib.getPackageName().equals(libInfo.getPackageName())) {
-            // If we are doing this while in the middle of updating a library apk,
-            // then we need to make sure to use that new apk for determining the
-            // dependencies here.  (We haven't yet finished committing the new apk
-            // to the package manager state.)
-            if (pkgForCodePaths == null
-                    || pkgForCodePaths.getPackageName().equals(changingLib.getPackageName())) {
-                pkgForCodePaths = changingLib;
-                pkgSetting = changingLibSetting;
-            }
-        }
-        if (pkgForCodePaths != null) {
-            usesLibraryFiles.addAll(AndroidPackageUtils.getAllCodePaths(pkgForCodePaths));
-            // If the package provides libraries, add the dependency to them.
-            applyDefiningSharedLibraryUpdateLocked(pkg, libInfo, SharedLibraryInfo::addDependency);
-            if (pkgSetting != null) {
-                usesLibraryFiles.addAll(pkgSetting.getPkgState().getUsesLibraryFiles());
-            }
-        }
-    }
-
-    @GuardedBy("mLock")
-    void updateSharedLibrariesLocked(AndroidPackage pkg, PackageSetting pkgSetting,
-            @Nullable AndroidPackage changingLib, @Nullable PackageSetting changingLibSetting,
-            Map<String, AndroidPackage> availablePackages)
-            throws PackageManagerException {
-        final ArrayList<SharedLibraryInfo> sharedLibraryInfos =
-                SharedLibraryHelper.collectSharedLibraryInfos(
-                        pkgSetting.getPkg(), availablePackages, mSharedLibraries,
-                        null /* newLibraries */, mInjector.getCompatibility());
-        executeSharedLibrariesUpdateLPr(pkg, pkgSetting, changingLib, changingLibSetting,
-                sharedLibraryInfos, mUserManager.getUserIds());
-    }
-
-    void executeSharedLibrariesUpdateLPr(AndroidPackage pkg,
-            @NonNull PackageSetting pkgSetting, @Nullable AndroidPackage changingLib,
-            @Nullable PackageSetting changingLibSetting,
-            ArrayList<SharedLibraryInfo> usesLibraryInfos, int[] allUsers) {
-        // If the package provides libraries, clear their old dependencies.
-        // This method will set them up again.
-        applyDefiningSharedLibraryUpdateLocked(pkg, null, (definingLibrary, dependency) -> {
-            definingLibrary.clearDependencies();
-        });
-        if (usesLibraryInfos != null) {
-            pkgSetting.getPkgState().setUsesLibraryInfos(usesLibraryInfos);
-            // Use LinkedHashSet to preserve the order of files added to
-            // usesLibraryFiles while eliminating duplicates.
-            Set<String> usesLibraryFiles = new LinkedHashSet<>();
-            for (SharedLibraryInfo libInfo : usesLibraryInfos) {
-                addSharedLibraryLPr(pkg, usesLibraryFiles, libInfo, changingLib,
-                        changingLibSetting);
-            }
-            pkgSetting.setPkgStateLibraryFiles(usesLibraryFiles);
-
-            // let's make sure we mark all static shared libraries as installed for the same users
-            // that its dependent packages are installed for.
-            int[] installedUsers = new int[allUsers.length];
-            int installedUserCount = 0;
-            for (int u = 0; u < allUsers.length; u++) {
-                if (pkgSetting.getInstalled(allUsers[u])) {
-                    installedUsers[installedUserCount++] = allUsers[u];
-                }
-            }
-            for (SharedLibraryInfo sharedLibraryInfo : usesLibraryInfos) {
-                if (!sharedLibraryInfo.isStatic()) {
-                    continue;
-                }
-                final PackageSetting staticLibPkgSetting =
-                        getPackageSettingForMutation(sharedLibraryInfo.getPackageName());
-                if (staticLibPkgSetting == null) {
-                    Slog.wtf(TAG, "Shared lib without setting: " + sharedLibraryInfo);
-                    continue;
-                }
-                for (int u = 0; u < installedUserCount; u++) {
-                    staticLibPkgSetting.setInstalled(true, installedUsers[u]);
-                }
-            }
-        } else {
-            pkgSetting.getPkgState().setUsesLibraryInfos(Collections.emptyList())
-                    .setUsesLibraryFiles(Collections.emptyList());
-        }
-    }
-
-    private static boolean hasString(List<String> list, List<String> which) {
-        if (list == null || which == null) {
-            return false;
-        }
-        for (int i=list.size()-1; i>=0; i--) {
-            for (int j=which.size()-1; j>=0; j--) {
-                if (which.get(j).equals(list.get(i))) {
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
-    @GuardedBy("mLock")
-    ArrayList<AndroidPackage> updateAllSharedLibrariesLocked(
-            @Nullable AndroidPackage updatedPkg, @Nullable PackageSetting updatedPkgSetting,
-            Map<String, AndroidPackage> availablePackages) {
-        ArrayList<AndroidPackage> resultList = null;
-        // Set of all descendants of a library; used to eliminate cycles
-        ArraySet<String> descendants = null;
-        // The current list of packages that need updating
-        List<Pair<AndroidPackage, PackageSetting>> needsUpdating = null;
-        if (updatedPkg != null && updatedPkgSetting != null) {
-            needsUpdating = new ArrayList<>(1);
-            needsUpdating.add(Pair.create(updatedPkg, updatedPkgSetting));
-        }
-        do {
-            final Pair<AndroidPackage, PackageSetting> changingPkgPair =
-                    (needsUpdating == null) ? null : needsUpdating.remove(0);
-            final AndroidPackage changingPkg = changingPkgPair != null
-                    ? changingPkgPair.first : null;
-            final PackageSetting changingPkgSetting = changingPkgPair != null
-                    ? changingPkgPair.second : null;
-            for (int i = mPackages.size() - 1; i >= 0; --i) {
-                final AndroidPackage pkg = mPackages.valueAt(i);
-                final PackageSetting pkgSetting = mSettings.getPackageLPr(pkg.getPackageName());
-                if (changingPkg != null
-                        && !hasString(pkg.getUsesLibraries(), changingPkg.getLibraryNames())
-                        && !hasString(pkg.getUsesOptionalLibraries(), changingPkg.getLibraryNames())
-                        && !ArrayUtils.contains(pkg.getUsesStaticLibraries(),
-                        changingPkg.getStaticSharedLibName())
-                        && !ArrayUtils.contains(pkg.getUsesSdkLibraries(),
-                        changingPkg.getSdkLibName())) {
-                    continue;
-                }
-                if (resultList == null) {
-                    resultList = new ArrayList<>();
-                }
-                resultList.add(pkg);
-                // if we're updating a shared library, all of its descendants must be updated
-                if (changingPkg != null) {
-                    if (descendants == null) {
-                        descendants = new ArraySet<>();
-                    }
-                    if (!descendants.contains(pkg.getPackageName())) {
-                        descendants.add(pkg.getPackageName());
-                        needsUpdating.add(Pair.create(pkg, pkgSetting));
-                    }
-                }
-                try {
-                    updateSharedLibrariesLocked(pkg, pkgSetting, changingPkg,
-                            changingPkgSetting, availablePackages);
-                } catch (PackageManagerException e) {
-                    // If a system app update or an app and a required lib missing we
-                    // delete the package and for updated system apps keep the data as
-                    // it is better for the user to reinstall than to be in an limbo
-                    // state. Also libs disappearing under an app should never happen
-                    // - just in case.
-                    if (!pkg.isSystem() || pkgSetting.getPkgState().isUpdatedSystemApp()) {
-                        final int flags = pkgSetting.getPkgState().isUpdatedSystemApp()
-                                ? PackageManager.DELETE_KEEP_DATA : 0;
-                        mDeletePackageHelper.deletePackageLIF(pkg.getPackageName(), null, true,
-                                mUserManager.getUserIds(), flags, null,
-                                true);
-                    }
-                    Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage());
-                }
-            }
-        } while (needsUpdating != null && needsUpdating.size() > 0);
-        return resultList;
-    }
-
-    @GuardedBy("mLock")
-    private void addBuiltInSharedLibraryLocked(SystemConfig.SharedLibraryEntry entry) {
-        if (nonStaticSharedLibExistsLocked(entry.name)) {
-            return;
-        }
-
-        SharedLibraryInfo libraryInfo = new SharedLibraryInfo(entry.filename, null, null,
-                entry.name, SharedLibraryInfo.VERSION_UNDEFINED,
-                SharedLibraryInfo.TYPE_BUILTIN,
-                new VersionedPackage(PLATFORM_PACKAGE_NAME, (long)0), null, null,
-                entry.isNative);
-
-        commitSharedLibraryInfoLocked(libraryInfo);
-    }
-
-    @GuardedBy("mLock")
-    private boolean nonStaticSharedLibExistsLocked(String name) {
-        return SharedLibraryHelper.sharedLibExists(name, SharedLibraryInfo.VERSION_UNDEFINED,
-                mSharedLibraries);
-    }
-
-    @GuardedBy("mLock")
-    void commitSharedLibraryInfoLocked(SharedLibraryInfo libraryInfo) {
-        final String name = libraryInfo.getName();
-        WatchedLongSparseArray<SharedLibraryInfo> versionedLib = mSharedLibraries.get(name);
-        if (versionedLib == null) {
-            versionedLib = new WatchedLongSparseArray<>();
-            mSharedLibraries.put(name, versionedLib);
-        }
-        final String declaringPackageName = libraryInfo.getDeclaringPackage().getPackageName();
-        if (libraryInfo.getType() == SharedLibraryInfo.TYPE_STATIC) {
-            mStaticLibsByDeclaringPackage.put(declaringPackageName, versionedLib);
-        }
-        versionedLib.put(libraryInfo.getLongVersion(), libraryInfo);
-    }
-
     @Override
     public Property getProperty(String propertyName, String packageName, String className) {
         Objects.requireNonNull(propertyName);
@@ -4909,8 +4570,8 @@
         if (pus.isSuspended()) {
             for (int i = 0; i < pus.getSuspendParams().size(); i++) {
                 final SuspendParams params = pus.getSuspendParams().valueAt(i);
-                if (params != null && params.appExtras != null) {
-                    allExtras.putAll(params.appExtras);
+                if (params != null && params.getAppExtras() != null) {
+                    allExtras.putAll(params.getAppExtras());
                 }
             }
         }
@@ -4983,9 +4644,9 @@
         synchronized (mLock) {
             for (String packageName : packagesToChange) {
                 final PackageSetting ps = mSettings.getPackageLPr(packageName);
-                if (ps != null && ps.getSuspended(userId)) {
+                if (ps != null && ps.getUserStateOrDefault(userId).isSuspended()) {
                     ps.removeSuspension(suspendingPackagePredicate, userId);
-                    if (!ps.getSuspended(userId)) {
+                    if (!ps.getUserStateOrDefault(userId).isSuspended()) {
                         unsuspendedPackages.add(ps.getPackageName());
                         unsuspendedUids.add(UserHandle.getUid(userId, ps.getAppId()));
                     }
@@ -7255,7 +6916,7 @@
      */
     void checkPackageFrozen(String packageName) {
         synchronized (mLock) {
-            if (!mFrozenPackages.contains(packageName)) {
+            if (!mFrozenPackages.containsKey(packageName)) {
                 Slog.wtf(TAG, "Expected " + packageName + " to be frozen!", new Throwable());
             }
         }
@@ -7769,8 +7430,8 @@
             if (userState.isSuspended()) {
                 for (int i = 0; i < userState.getSuspendParams().size(); i++) {
                     final SuspendParams params = userState.getSuspendParams().valueAt(i);
-                    if (params != null && params.launcherExtras != null) {
-                        allExtras.putAll(params.launcherExtras);
+                    if (params != null && params.getLauncherExtras() != null) {
+                        allExtras.putAll(params.getLauncherExtras());
                     }
                 }
             }
@@ -7859,7 +7520,7 @@
             }
 
             final SuspendParams suspendParams = suspendParamsMap.get(suspendingPackage);
-            return (suspendParams != null) ? suspendParams.dialogInfo : null;
+            return (suspendParams != null) ? suspendParams.getDialogInfo() : null;
         }
 
         @Override
@@ -8305,7 +7966,13 @@
         @Override
         public void forEachInstalledPackage(@NonNull Consumer<AndroidPackage> actionLocked,
                 @UserIdInt int userId) {
-            PackageManagerService.this.forEachInstalledPackage(actionLocked, userId);
+            forEachInstalledPackage(true, actionLocked, userId);
+        }
+
+        @Override
+        public void forEachInstalledPackage(boolean locked,
+                @NonNull Consumer<AndroidPackage> action, int userId) {
+            PackageManagerService.this.forEachInstalledPackage(locked, action, userId);
         }
 
         @Override
@@ -8578,51 +8245,24 @@
         @Override
         public void withPackageSettingsSnapshot(
                 @NonNull Consumer<Function<String, PackageStateInternal>> block) {
-            final Computer snapshot = snapshotComputer();
-
-            // This method needs to either lock or not lock consistently throughout the method,
-            // so if the live computer is returned, force a wrapping sync block.
-            if (snapshot == mLiveComputer) {
-                synchronized (mLock) {
-                    block.accept(snapshot::getPackageStateInternal);
-                }
-            } else {
-                block.accept(snapshot::getPackageStateInternal);
-            }
+            executeWithConsistentComputer(computer ->
+                    block.accept(computer::getPackageStateInternal));
         }
 
         @Override
         public <Output> Output withPackageSettingsSnapshotReturning(
                 @NonNull FunctionalUtils.ThrowingFunction<Function<String, PackageStateInternal>,
                         Output> block) {
-            final Computer snapshot = snapshotComputer();
-
-            // This method needs to either lock or not lock consistently throughout the method,
-            // so if the live computer is returned, force a wrapping sync block.
-            if (snapshot == mLiveComputer) {
-                synchronized (mLock) {
-                    return block.apply(snapshot::getPackageStateInternal);
-                }
-            } else {
-                return block.apply(snapshot::getPackageStateInternal);
-            }
+            return executeWithConsistentComputerReturning(computer ->
+                    block.apply(computer::getPackageStateInternal));
         }
 
         @Override
         public <ExceptionType extends Exception> void withPackageSettingsSnapshotThrowing(
                 @NonNull FunctionalUtils.ThrowingCheckedConsumer<Function<String,
                         PackageStateInternal>, ExceptionType> block) throws ExceptionType {
-            final Computer snapshot = snapshotComputer();
-
-            // This method needs to either lock or not lock consistently throughout the method,
-            // so if the live computer is returned, force a wrapping sync block.
-            if (snapshot == mLiveComputer) {
-                synchronized (mLock) {
-                    block.accept(snapshot::getPackageStateInternal);
-                }
-            } else {
-                block.accept(snapshot::getPackageStateInternal);
-            }
+            executeWithConsistentComputerThrowing(computer ->
+                    block.accept(computer::getPackageStateInternal));
         }
 
         @Override
@@ -8632,17 +8272,9 @@
                                 Function<String, PackageStateInternal>, ExceptionOne,
                                 ExceptionTwo> block)
                 throws ExceptionOne, ExceptionTwo {
-            final Computer snapshot = snapshotComputer();
-
-            // This method needs to either lock or not lock consistently throughout the method,
-            // so if the live computer is returned, force a wrapping sync block.
-            if (snapshot == mLiveComputer) {
-                synchronized (mLock) {
-                    block.accept(snapshot::getPackageStateInternal);
-                }
-            } else {
-                block.accept(snapshot::getPackageStateInternal);
-            }
+            executeWithConsistentComputerThrowing2(
+                    (FunctionalUtils.ThrowingChecked2Consumer<Computer, ExceptionOne,
+                            ExceptionTwo>) computer -> block.accept(computer::getPackageStateInternal));
         }
 
         @Override
@@ -8652,17 +8284,8 @@
                                 Function<String, PackageStateInternal>, Output,
                                 ExceptionType> block)
                 throws ExceptionType {
-            final Computer snapshot = snapshotComputer();
-
-            // This method needs to either lock or not lock consistently throughout the method,
-            // so if the live computer is returned, force a wrapping sync block.
-            if (snapshot == mLiveComputer) {
-                synchronized (mLock) {
-                    return block.apply(snapshot::getPackageStateInternal);
-                }
-            } else {
-                return block.apply(snapshot::getPackageStateInternal);
-            }
+            return executeWithConsistentComputerReturningThrowing(computer ->
+                    block.apply(computer::getPackageStateInternal));
         }
 
         @Override
@@ -8671,6 +8294,20 @@
             PackageManagerService.this.mAppDataHelper.reconcileAppsData(userId, flags,
                     migrateAppsData);
         }
+
+        @NonNull
+        @Override
+        public PackageStateMutator.InitialState recordInitialState() {
+            return PackageManagerService.this.recordInitialState();
+        }
+
+        @Nullable
+        @Override
+        public PackageStateMutator.Result commitPackageStateMutation(
+                @Nullable PackageStateMutator.InitialState state,
+                @NonNull Consumer<PackageStateMutator> consumer) {
+            return PackageManagerService.this.commitPackageStateMutation(state, consumer);
+        }
     }
 
     @Override
@@ -8713,7 +8350,15 @@
     @Nullable
     @GuardedBy("mLock")
     PackageSetting getPackageSettingForMutation(String packageName) {
-        return (PackageSetting) mComputer.getPackageStateInternal(packageName);
+        return mSettings.getPackageLPr(packageName);
+    }
+
+    // TODO: Remove
+    @Deprecated
+    @Nullable
+    @GuardedBy("mLock")
+    PackageSetting getDisabledPackageSettingForMutation(String packageName) {
+        return mSettings.getDisabledSystemPkgLPr(packageName);
     }
 
     @VisibleForTesting(visibility = Visibility.PRIVATE)
@@ -8721,7 +8366,7 @@
     PackageStateInternal getPackageStateInternal(String packageName) {
         Computer computer = snapshotComputer();
         if (computer == mLiveComputer) {
-            synchronized (mLock) {
+            synchronized (mLiveComputerSyncLock) {
                 PackageSetting pkgSetting =
                         (PackageSetting) computer.getPackageStateInternal(packageName);
                 if (pkgSetting == null) {
@@ -8730,15 +8375,16 @@
 
                 return new PackageSetting(pkgSetting);
             }
+        } else {
+            return computer.getPackageStateInternal(packageName);
         }
-        return computer.getPackageStateInternal(packageName);
     }
 
     @Nullable
     PackageStateInternal getPackageStateInternal(String packageName, int callingUid) {
         Computer computer = snapshotComputer();
         if (computer == mLiveComputer) {
-            synchronized (mLock) {
+            synchronized (mLiveComputerSyncLock) {
                 PackageSetting pkgSetting =
                         (PackageSetting) computer.getPackageStateInternal(packageName, callingUid);
                 if (pkgSetting == null) {
@@ -8747,8 +8393,9 @@
 
                 return new PackageSetting(pkgSetting);
             }
+        } else {
+            return computer.getPackageStateInternal(packageName, callingUid);
         }
-        return computer.getPackageStateInternal(packageName, callingUid);
     }
 
     @Nullable
@@ -8756,7 +8403,7 @@
             int callingUid, @UserIdInt int userId) {
         Computer computer = snapshotComputer();
         if (computer == mLiveComputer) {
-            synchronized (mLock) {
+            synchronized (mLiveComputerSyncLock) {
                 PackageSetting pkgSetting =
                         (PackageSetting) filterPackageStateForInstalledAndFiltered(computer,
                                 packageName, callingUid, userId);
@@ -8765,9 +8412,10 @@
                 }
                 return new PackageSetting(pkgSetting);
             }
+        } else {
+            return filterPackageStateForInstalledAndFiltered(computer, packageName, callingUid,
+                    userId);
         }
-
-        return filterPackageStateForInstalledAndFiltered(computer, packageName, callingUid, userId);
     }
 
     @Nullable
@@ -8795,16 +8443,8 @@
         Computer computer = snapshotComputer();
         if (computer == mLiveComputer) {
             return new ArrayMap<>(computer.getPackageStates());
-        }
-        return computer.getPackageStates();
-    }
-
-    void forEachPackage(Consumer<AndroidPackage> actionLocked) {
-        synchronized (mLock) {
-            int numPackages = mPackages.size();
-            for (int i = 0; i < numPackages; i++) {
-                actionLocked.accept(mPackages.valueAt(i));
-            }
+        } else {
+            return computer.getPackageStates();
         }
     }
 
@@ -8817,17 +8457,31 @@
         }
     }
 
-    private void forEachPackageState(boolean locked, Consumer<PackageStateInternal> action) {
+    void forEachPackageState(boolean locked, Consumer<PackageStateInternal> action) {
         if (locked) {
-            forEachPackageSetting(action::accept);
+            synchronized (mLiveComputerSyncLock) {
+                forEachPackageState(mComputer.getPackageStates(), action);
+            }
         } else {
             Computer computer = snapshotComputer();
             if (computer == mLiveComputer) {
-                synchronized (mLock) {
+                synchronized (mLiveComputerSyncLock) {
                     forEachPackageState(computer.getPackageStates(), action);
-                };
+                }
+            } else {
+                forEachPackageState(computer.getPackageStates(), action);
             }
-            forEachPackageState(computer.getPackageStates(), action);
+        }
+    }
+
+    void forEachPackage(Consumer<AndroidPackage> action) {
+        Computer computer = snapshotComputer();
+        if (computer == mLiveComputer) {
+            synchronized (mLiveComputerSyncLock) {
+                forEachPackage(computer.getPackageStates(), action);
+            }
+        } else {
+            forEachPackage(computer.getPackageStates(), action);
         }
     }
 
@@ -8841,21 +8495,106 @@
         }
     }
 
-    void forEachInstalledPackage(@NonNull Consumer<AndroidPackage> actionLocked,
-            @UserIdInt int userId) {
-        synchronized (mLock) {
-            int numPackages = mPackages.size();
-            for (int i = 0; i < numPackages; i++) {
-                AndroidPackage pkg = mPackages.valueAt(i);
-                PackageSetting setting = mSettings.getPackageLPr(pkg.getPackageName());
-                if (setting == null || !setting.getInstalled(userId)) {
-                    continue;
-                }
-                actionLocked.accept(pkg);
+    private void forEachPackage(
+            @NonNull ArrayMap<String, ? extends PackageStateInternal> packageStates,
+            @NonNull Consumer<AndroidPackage> consumer) {
+        int size = packageStates.size();
+        for (int index = 0; index < size; index++) {
+            PackageStateInternal packageState = packageStates.valueAt(index);
+            if (packageState.getPkg() != null) {
+                consumer.accept(packageState.getPkg());
             }
         }
     }
 
+    void forEachInstalledPackage(boolean locked, @NonNull Consumer<AndroidPackage> action,
+            @UserIdInt int userId) {
+        Consumer<PackageStateInternal> actionWrapped = packageState -> {
+            if (packageState.getPkg() != null
+                    && packageState.getUserStateOrDefault(userId).isInstalled()) {
+                action.accept(packageState.getPkg());
+            }
+        };
+        if (locked) {
+            synchronized (mLiveComputerSyncLock) {
+                forEachPackageState(mComputer.getPackageStates(), actionWrapped);
+            }
+        } else {
+            Computer computer = snapshotComputer();
+            if (computer == mLiveComputer) {
+                synchronized (mLiveComputerSyncLock) {
+                    forEachPackageState(computer.getPackageStates(), actionWrapped);
+                }
+            } else {
+                forEachPackageState(computer.getPackageStates(), actionWrapped);
+            }
+        }
+    }
+
+    private void executeWithConsistentComputer(
+            @NonNull FunctionalUtils.ThrowingConsumer<Computer> consumer) {
+        Computer computer = snapshotComputer();
+        if (computer == mLiveComputer) {
+            synchronized (mLiveComputerSyncLock) {
+                consumer.accept(computer);
+            }
+        } else {
+            consumer.accept(computer);
+        }
+    }
+
+    private <T> T executeWithConsistentComputerReturning(
+            @NonNull FunctionalUtils.ThrowingFunction<Computer, T> function) {
+        Computer computer = snapshotComputer();
+        if (computer == mLiveComputer) {
+            synchronized (mLiveComputerSyncLock) {
+                return function.apply(computer);
+            }
+        } else {
+            return function.apply(computer);
+        }
+    }
+
+    private <ExceptionType extends Exception> void executeWithConsistentComputerThrowing(
+            @NonNull FunctionalUtils.ThrowingCheckedConsumer<Computer, ExceptionType> consumer)
+            throws ExceptionType {
+        Computer computer = snapshotComputer();
+        if (computer == mLiveComputer) {
+            synchronized (mLiveComputerSyncLock) {
+                consumer.accept(computer);
+            }
+        } else {
+            consumer.accept(computer);
+        }
+    }
+
+    private <ExceptionOne extends Exception, ExceptionTwo extends Exception> void
+    executeWithConsistentComputerThrowing2(
+            @NonNull FunctionalUtils.ThrowingChecked2Consumer<Computer, ExceptionOne,
+                    ExceptionTwo> consumer) throws ExceptionOne, ExceptionTwo {
+        Computer computer = snapshotComputer();
+        if (computer == mLiveComputer) {
+            synchronized (mLiveComputerSyncLock) {
+                consumer.accept(computer);
+            }
+        } else {
+            consumer.accept(computer);
+        }
+    }
+
+    private <T, ExceptionType extends Exception> T executeWithConsistentComputerReturningThrowing(
+            @NonNull FunctionalUtils.ThrowingCheckedFunction<Computer, T, ExceptionType> function)
+            throws ExceptionType {
+        Computer computer = snapshotComputer();
+        if (computer == mLiveComputer) {
+            synchronized (mLiveComputerSyncLock) {
+                return function.apply(computer);
+            }
+        } else {
+            return function.apply(computer);
+        }
+    }
+
     boolean isHistoricalPackageUsageAvailable() {
         return mPackageUsage.isHistoricalPackageUsageAvailable();
     }
@@ -9051,7 +8790,8 @@
         enforceOwnerRights(packageName, Binder.getCallingUid());
         final boolean changed;
         synchronized (mLock) {
-            changed = mSettings.getPackageLPr(packageName).setMimeGroup(mimeGroup, mimeTypes);
+            changed = mSettings.getPackageLPr(packageName).setMimeGroup(mimeGroup,
+                    new ArraySet<>(mimeTypes));
         }
         if (changed) {
             applyMimeGroupChanges(packageName, mimeGroup);
@@ -9510,7 +9250,8 @@
     }
 
     boolean isOverlayMutable(String packageName) {
-        return mOverlayConfig.isMutable(packageName);
+        return (mOverlayConfig != null ? mOverlayConfig
+                : OverlayConfig.getSystemInstance()).isMutable(packageName);
     }
 
     @ScanFlags int getSystemPackageScanFlags(File codePath) {
@@ -9553,4 +9294,62 @@
         return new Pair<>(rescanFlags, reparseFlags);
     }
 
+
+    /**
+     * @see PackageManagerInternal#recordInitialState()
+     */
+    @NonNull
+    public PackageStateMutator.InitialState recordInitialState() {
+        return mPackageStateMutator.initialState(mChangedPackagesSequenceNumber);
+    }
+
+    /**
+     * @see PackageManagerInternal#commitPackageStateMutation(PackageStateMutator.InitialState,
+     * Consumer)
+     */
+    @NonNull
+    public PackageStateMutator.Result commitPackageStateMutation(
+            @Nullable PackageStateMutator.InitialState initialState,
+            @NonNull Consumer<PackageStateMutator> consumer) {
+        synchronized (mPackageStateWriteLock) {
+            final PackageStateMutator.Result result = mPackageStateMutator.generateResult(
+                    initialState, mChangedPackagesSequenceNumber);
+            if (result != PackageStateMutator.Result.SUCCESS) {
+                return result;
+            }
+
+            consumer.accept(mPackageStateMutator);
+            onChanged();
+        }
+
+        return PackageStateMutator.Result.SUCCESS;
+    }
+
+    /**
+     * @see PackageManagerInternal#commitPackageStateMutation(PackageStateMutator.InitialState,
+     * Consumer)
+     */
+    @NonNull
+    public PackageStateMutator.Result commitPackageStateMutation(
+            @Nullable PackageStateMutator.InitialState initialState, @NonNull String packageName,
+            @NonNull Consumer<PackageStateWrite> consumer) {
+        synchronized (mPackageStateWriteLock) {
+            final PackageStateMutator.Result result = mPackageStateMutator.generateResult(
+                    initialState, mChangedPackagesSequenceNumber);
+            if (result != PackageStateMutator.Result.SUCCESS) {
+                return result;
+            }
+
+            PackageStateWrite state = mPackageStateMutator.forPackage(packageName);
+            if (state == null) {
+                return PackageStateMutator.Result.SPECIFIC_PACKAGE_NULL;
+            } else {
+                consumer.accept(state);
+            }
+
+            onChanged();
+        }
+
+        return PackageStateMutator.Result.SUCCESS;
+    }
 }
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceInjector.java b/services/core/java/com/android/server/pm/PackageManagerServiceInjector.java
index d14cc1f..05bb01e 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceInjector.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceInjector.java
@@ -137,6 +137,7 @@
     private final Singleton<Handler> mHandlerProducer;
     private final Singleton<BackgroundDexOptService> mBackgroundDexOptService;
     private final Singleton<IBackupManager> mIBackupManager;
+    private final Singleton<SharedLibrariesImpl> mSharedLibrariesProducer;
 
     PackageManagerServiceInjector(Context context, PackageManagerTracedLock lock,
             Installer installer, Object installLock, PackageAbiHelper abiHelper,
@@ -173,7 +174,8 @@
             ServiceProducer getLocalServiceProducer,
             ServiceProducer getSystemServiceProducer,
             Producer<BackgroundDexOptService> backgroundDexOptService,
-            Producer<IBackupManager> iBackupManager) {
+            Producer<IBackupManager> iBackupManager,
+            Producer<SharedLibrariesImpl> sharedLibrariesProducer) {
         mContext = context;
         mLock = lock;
         mInstaller = installer;
@@ -224,6 +226,7 @@
         mHandlerProducer = new Singleton<>(handlerProducer);
         mBackgroundDexOptService = new Singleton<>(backgroundDexOptService);
         mIBackupManager = new Singleton<>(iBackupManager);
+        mSharedLibrariesProducer = new Singleton<>(sharedLibrariesProducer);
     }
 
     /**
@@ -392,6 +395,10 @@
         return mIBackupManager.get(this, mPackageManager);
     }
 
+    public SharedLibrariesImpl getSharedLibrariesImpl() {
+        return mSharedLibrariesProducer.get(this, mPackageManager);
+    }
+
     /** Provides an abstraction to static access to system state. */
     public interface SystemWrapper {
         void disablePackageCaches();
diff --git a/services/core/java/com/android/server/pm/PackageSessionVerifier.java b/services/core/java/com/android/server/pm/PackageSessionVerifier.java
index 4f21d0e..a532fe3 100644
--- a/services/core/java/com/android/server/pm/PackageSessionVerifier.java
+++ b/services/core/java/com/android/server/pm/PackageSessionVerifier.java
@@ -45,6 +45,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.content.PackageHelper;
 import com.android.server.LocalServices;
+import com.android.server.SystemConfig;
 import com.android.server.pm.parsing.PackageParser2;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
 import com.android.server.rollback.RollbackManagerInternal;
@@ -99,9 +100,11 @@
                 storeSession(session.mStagedSession);
                 if (session.isMultiPackage()) {
                     for (PackageInstallerSession child : session.getChildSessions()) {
+                        checkApexUpdateAllowed(child);
                         checkRebootlessApex(child);
                     }
                 } else {
+                    checkApexUpdateAllowed(session);
                     checkRebootlessApex(session);
                 }
                 verifyAPK(session, callback);
@@ -203,7 +206,7 @@
     }
 
     private void onVerificationFailure(StagingManager.StagedSession session, Callback callback,
-            @SessionInfo.StagedSessionErrorCode int errorCode, String errorMessage) {
+            @SessionInfo.SessionErrorCode int errorCode, String errorMessage) {
         if (!ensureActiveApexSessionIsAborted(session)) {
             Slog.e(TAG, "Failed to abort apex session " + session.sessionId());
             // Safe to ignore active apex session abortion failure since session will be marked
@@ -461,6 +464,51 @@
         return mApexManager.abortStagedSession(sessionId);
     }
 
+    private boolean isApexUpdateAllowed(String apexPackageName, String installerPackageName) {
+        if (mPm.getModuleInfo(apexPackageName, 0) != null) {
+            final String modulesInstaller =
+                    SystemConfig.getInstance().getModulesInstallerPackageName();
+            if (modulesInstaller == null) {
+                Slog.w(TAG, "No modules installer defined");
+                return false;
+            }
+            return modulesInstaller.equals(installerPackageName);
+        }
+        final String vendorApexInstaller =
+                SystemConfig.getInstance().getAllowedVendorApexes().get(apexPackageName);
+        if (vendorApexInstaller == null) {
+            Slog.w(TAG, apexPackageName + " is not allowed to be updated");
+            return false;
+        }
+        return vendorApexInstaller.equals(installerPackageName);
+    }
+
+    /**
+     * Checks if APEX update is allowed.
+     *
+     * This phase is shared between staged and non-staged sessions and should be called after
+     * boot is completed since this check depends on the ModuleInfoProvider, which is only populated
+     * after device has booted.
+     */
+    private void checkApexUpdateAllowed(PackageInstallerSession session)
+            throws PackageManagerException {
+        if (!session.isApexSession()) {
+            return;
+        }
+        final int installFlags = session.params.installFlags;
+        if ((installFlags & PackageManager.INSTALL_DISABLE_ALLOWED_APEX_UPDATE_CHECK) != 0) {
+            return;
+        }
+        final String packageName = session.getPackageName();
+        final String installerPackageName = session.getInstallSource().installerPackageName;
+        if (!isApexUpdateAllowed(packageName, installerPackageName)) {
+            throw new PackageManagerException(
+                    PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
+                    "Update of APEX package " + packageName + " is not allowed for "
+                            + installerPackageName);
+        }
+    }
+
     /**
      * Fails this rebootless APEX session if the same package name found in any staged sessions.
      */
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 923a133..9dbf57d 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -33,6 +33,7 @@
 import android.content.pm.UserInfo;
 import android.content.pm.overlay.OverlayPaths;
 import android.os.PersistableBundle;
+import android.os.UserHandle;
 import android.service.pm.PackageProto;
 import android.util.ArrayMap;
 import android.util.ArraySet;
@@ -157,7 +158,6 @@
     private String mCpuAbiOverride;
 
     private long mLastModifiedTime;
-    private long firstInstallTime;
     private long lastUpdateTime;
     private long versionCode;
 
@@ -284,7 +284,6 @@
         proto.write(PackageProto.NAME, (mRealName != null ? mRealName : mName));
         proto.write(PackageProto.UID, mAppId);
         proto.write(PackageProto.VERSION_CODE, versionCode);
-        proto.write(PackageProto.INSTALL_TIME_MS, firstInstallTime);
         proto.write(PackageProto.UPDATE_TIME_MS, lastUpdateTime);
         proto.write(PackageProto.INSTALLER_NAME, installSource.installerPackageName);
 
@@ -335,8 +334,36 @@
         return this;
     }
 
-    public PackageSetting setFirstInstallTime(long firstInstallTime) {
-        this.firstInstallTime = firstInstallTime;
+    /**
+     * In case of replacing an old package, restore the first install timestamps if it was installed
+     * for the same users
+     */
+    public PackageSetting setFirstInstallTimeFromReplaced(PackageStateInternal replacedPkgSetting,
+            int[] userIds) {
+        for (int userId = 0; userId < userIds.length; userId++) {
+            final long previousFirstInstallTime =
+                    replacedPkgSetting.getUserStateOrDefault(userId).getFirstInstallTime();
+            if (previousFirstInstallTime != 0) {
+                modifyUserState(userId).setFirstInstallTime(previousFirstInstallTime);
+            }
+        }
+        onChanged();
+        return this;
+    }
+
+    /**
+     * Set the time for the first time when an app is installed for a user. If userId specifies all
+     * users, set the same timestamp for all the users.
+     */
+    public PackageSetting setFirstInstallTime(long firstInstallTime, int userId) {
+        if (userId == UserHandle.USER_ALL) {
+            int userStateCount = mUserStates.size();
+            for (int i = 0; i < userStateCount; i++) {
+                mUserStates.valueAt(i).setFirstInstallTime(firstInstallTime);
+            }
+        } else {
+            modifyUserState(userId).setFirstInstallTime(firstInstallTime);
+        }
         onChanged();
         return this;
     }
@@ -395,14 +422,13 @@
         return this;
     }
 
-    public boolean setMimeGroup(String mimeGroup, List<String> mimeTypes) {
+    public boolean setMimeGroup(String mimeGroup, ArraySet<String> newMimeTypes) {
         Set<String> oldMimeTypes = mimeGroups == null ? null : mimeGroups.get(mimeGroup);
         if (oldMimeTypes == null) {
             throw new IllegalArgumentException("Unknown MIME group " + mimeGroup
                     + " for package " + mName);
         }
 
-        ArraySet<String> newMimeTypes = new ArraySet<>(mimeTypes);
         boolean hasChanges = !newMimeTypes.equals(oldMimeTypes);
         mimeGroups.put(mimeGroup, newMimeTypes);
         if (hasChanges) {
@@ -613,7 +639,6 @@
         mSecondaryCpuAbi = other.mSecondaryCpuAbi;
         mCpuAbiOverride = other.mCpuAbiOverride;
         mLastModifiedTime = other.mLastModifiedTime;
-        firstInstallTime = other.firstInstallTime;
         lastUpdateTime = other.lastUpdateTime;
         versionCode = other.versionCode;
         signatures = other.signatures;
@@ -670,6 +695,15 @@
         return state;
     }
 
+    public PackageUserStateImpl getOrCreateUserState(@UserIdInt int userId) {
+        PackageUserStateImpl state = mUserStates.get(userId);
+        if (state == null) {
+            state = new PackageUserStateImpl();
+            mUserStates.put(userId, state);
+        }
+        return state;
+    }
+
     @NonNull
     public PackageUserStateInternal readUserState(int userId) {
         PackageUserStateInternal state = mUserStates.get(userId);
@@ -832,7 +866,6 @@
         }
         final SuspendParams oldSuspendParams =
                 existingUserState.getSuspendParams().put(suspendingPackage, newSuspendParams);
-        existingUserState.setSuspended(true);
         onChanged();
         return !Objects.equals(oldSuspendParams, newSuspendParams);
     }
@@ -848,7 +881,6 @@
                 existingUserState.setSuspendParams(null);
             }
         }
-        existingUserState.setSuspended((existingUserState.getSuspendParams() != null));
         onChanged();
         return wasModified;
     }
@@ -866,7 +898,6 @@
                 existingUserState.setSuspendParams(null);
             }
         }
-        existingUserState.setSuspended((existingUserState.getSuspendParams() != null));
         onChanged();
     }
 
@@ -889,12 +920,13 @@
     }
 
     void setUserState(int userId, long ceDataInode, int enabled, boolean installed, boolean stopped,
-            boolean notLaunched, boolean hidden, int distractionFlags, boolean suspended,
+            boolean notLaunched, boolean hidden, int distractionFlags,
             ArrayMap<String, SuspendParams> suspendParams, boolean instantApp,
             boolean virtualPreload, String lastDisableAppCaller,
             ArraySet<String> enabledComponents, ArraySet<String> disabledComponents,
             int installReason, int uninstallReason,
-            String harmfulAppWarning, String splashScreenTheme) {
+            String harmfulAppWarning, String splashScreenTheme,
+            long firstInstallTime) {
         modifyUserState(userId)
                 .setSuspendParams(suspendParams)
                 .setCeDataInode(ceDataInode)
@@ -904,7 +936,6 @@
                 .setNotLaunched(notLaunched)
                 .setHidden(hidden)
                 .setDistractionFlags(distractionFlags)
-                .setSuspended(suspended)
                 .setLastDisableAppCaller(lastDisableAppCaller)
                 .setEnabledComponents(enabledComponents)
                 .setDisabledComponents(disabledComponents)
@@ -913,22 +944,22 @@
                 .setInstantApp(instantApp)
                 .setVirtualPreload(virtualPreload)
                 .setHarmfulAppWarning(harmfulAppWarning)
-                .setSplashScreenTheme(splashScreenTheme);
+                .setSplashScreenTheme(splashScreenTheme)
+                .setFirstInstallTime(firstInstallTime);
         onChanged();
     }
 
     void setUserState(int userId, PackageUserStateInternal otherState) {
         setUserState(userId, otherState.getCeDataInode(), otherState.getEnabledState(),
-                otherState.isInstalled(),
-                otherState.isStopped(), otherState.isNotLaunched(), otherState.isHidden(),
-                otherState.getDistractionFlags(), otherState.isSuspended(),
-                otherState.getSuspendParams(),
-                otherState.isInstantApp(),
+                otherState.isInstalled(), otherState.isStopped(), otherState.isNotLaunched(),
+                otherState.isHidden(), otherState.getDistractionFlags(),
+                otherState.getSuspendParams(), otherState.isInstantApp(),
                 otherState.isVirtualPreload(), otherState.getLastDisableAppCaller(),
                 new ArraySet<>(otherState.getEnabledComponentsNoCopy()),
                 new ArraySet<>(otherState.getDisabledComponentsNoCopy()),
                 otherState.getInstallReason(), otherState.getUninstallReason(),
-                otherState.getHarmfulAppWarning(), otherState.getSplashScreenTheme());
+                otherState.getHarmfulAppWarning(), otherState.getSplashScreenTheme(),
+                otherState.getFirstInstallTime());
     }
 
     ArraySet<String> getEnabledComponents(int userId) {
@@ -1119,6 +1150,8 @@
             proto.write(
                     PackageProto.UserInfoProto.LAST_DISABLED_APP_CALLER,
                     state.getLastDisableAppCaller());
+            proto.write(PackageProto.UserInfoProto.FIRST_INSTALL_TIME_MS,
+                    state.getFirstInstallTime());
             proto.end(userToken);
         }
     }
@@ -1484,11 +1517,6 @@
     }
 
     @DataClass.Generated.Member
-    public long getFirstInstallTime() {
-        return firstInstallTime;
-    }
-
-    @DataClass.Generated.Member
     public long getLastUpdateTime() {
         return lastUpdateTime;
     }
@@ -1553,10 +1581,10 @@
     }
 
     @DataClass.Generated(
-            time = 1635870549646L,
+            time = 1640923794772L,
             codegenVersion = "1.0.23",
             sourceFile = "frameworks/base/services/core/java/com/android/server/pm/PackageSetting.java",
-            inputSignatures = "private  int sharedUserId\nprivate @android.annotation.Nullable java.util.Map<java.lang.String,java.util.Set<java.lang.String>> mimeGroups\nprivate @java.lang.Deprecated @android.annotation.Nullable java.util.Set<java.lang.String> mOldCodePaths\nprivate @android.annotation.Nullable java.lang.String[] usesStaticLibraries\nprivate @android.annotation.Nullable long[] usesStaticLibrariesVersions\nprivate @android.annotation.Nullable @java.lang.Deprecated java.lang.String legacyNativeLibraryPath\nprivate @android.annotation.NonNull java.lang.String mName\nprivate @android.annotation.Nullable java.lang.String mRealName\nprivate  int mAppId\nprivate @android.annotation.Nullable com.android.server.pm.parsing.pkg.AndroidPackage pkg\nprivate @android.annotation.Nullable com.android.server.pm.SharedUserSetting sharedUser\nprivate @android.annotation.NonNull java.io.File mPath\nprivate @android.annotation.NonNull java.lang.String mPathString\nprivate  float mLoadingProgress\nprivate @android.annotation.Nullable java.lang.String mPrimaryCpuAbi\nprivate @android.annotation.Nullable java.lang.String mSecondaryCpuAbi\nprivate @android.annotation.Nullable java.lang.String mCpuAbiOverride\nprivate  long mLastModifiedTime\nprivate  long firstInstallTime\nprivate  long lastUpdateTime\nprivate  long versionCode\nprivate @android.annotation.NonNull com.android.server.pm.PackageSignatures signatures\nprivate  boolean installPermissionsFixed\nprivate @android.annotation.NonNull com.android.server.pm.PackageKeySetData keySetData\nprivate final @android.annotation.NonNull android.util.SparseArray<com.android.server.pm.pkg.PackageUserStateImpl> mUserStates\nprivate @android.annotation.NonNull com.android.server.pm.InstallSource installSource\nprivate @android.annotation.Nullable java.lang.String volumeUuid\nprivate  int categoryOverride\nprivate  boolean updateAvailable\nprivate  boolean forceQueryableOverride\nprivate @android.annotation.NonNull com.android.server.pm.pkg.PackageStateUnserialized pkgState\nprivate @android.annotation.NonNull java.util.UUID mDomainSetId\nprivate final @android.annotation.NonNull com.android.server.utils.SnapshotCache<com.android.server.pm.PackageSetting> mSnapshot\nprivate  com.android.server.utils.SnapshotCache<com.android.server.pm.PackageSetting> makeCache()\npublic  com.android.server.pm.PackageSetting snapshot()\npublic  void dumpDebug(android.util.proto.ProtoOutputStream,long,java.util.List<android.content.pm.UserInfo>,com.android.server.pm.permission.LegacyPermissionDataProvider)\npublic  java.util.List<java.lang.String> getMimeGroup(java.lang.String)\nprivate  java.util.Set<java.lang.String> getMimeGroupInternal(java.lang.String)\npublic  boolean isSharedUser()\npublic  com.android.server.pm.PackageSetting setAppId(int)\npublic  com.android.server.pm.PackageSetting setCpuAbiOverride(java.lang.String)\npublic  com.android.server.pm.PackageSetting setFirstInstallTime(long)\npublic  com.android.server.pm.PackageSetting setForceQueryableOverride(boolean)\npublic  com.android.server.pm.PackageSetting setInstallerPackageName(java.lang.String)\npublic  com.android.server.pm.PackageSetting setInstallSource(com.android.server.pm.InstallSource)\n  com.android.server.pm.PackageSetting removeInstallerPackage(java.lang.String)\npublic  com.android.server.pm.PackageSetting setIsOrphaned(boolean)\npublic  com.android.server.pm.PackageSetting setKeySetData(com.android.server.pm.PackageKeySetData)\npublic  com.android.server.pm.PackageSetting setLastModifiedTime(long)\npublic  com.android.server.pm.PackageSetting setLastUpdateTime(long)\npublic  com.android.server.pm.PackageSetting setLongVersionCode(long)\npublic  boolean setMimeGroup(java.lang.String,java.util.List<java.lang.String>)\npublic  com.android.server.pm.PackageSetting setPkg(com.android.server.pm.parsing.pkg.AndroidPackage)\npublic  com.android.server.pm.PackageSetting setPrimaryCpuAbi(java.lang.String)\npublic  com.android.server.pm.PackageSetting setSecondaryCpuAbi(java.lang.String)\npublic  com.android.server.pm.PackageSetting setSignatures(com.android.server.pm.PackageSignatures)\npublic  com.android.server.pm.PackageSetting setVolumeUuid(java.lang.String)\npublic @java.lang.Override boolean isExternalStorage()\npublic  com.android.server.pm.PackageSetting setUpdateAvailable(boolean)\npublic  int getSharedUserIdInt()\npublic @java.lang.Override java.lang.String toString()\nprotected  void copyMimeGroups(java.util.Map<java.lang.String,java.util.Set<java.lang.String>>)\npublic  void updateFrom(com.android.server.pm.PackageSetting)\n  com.android.server.pm.PackageSetting updateMimeGroups(java.util.Set<java.lang.String>)\npublic @java.lang.Deprecated @java.lang.Override com.android.server.pm.permission.LegacyPermissionState getLegacyPermissionState()\npublic  com.android.server.pm.PackageSetting setInstallPermissionsFixed(boolean)\npublic  boolean isPrivileged()\npublic  boolean isOem()\npublic  boolean isVendor()\npublic  boolean isProduct()\npublic @java.lang.Override boolean isRequiredForSystemUser()\npublic  boolean isSystemExt()\npublic  boolean isOdm()\npublic  boolean isSystem()\npublic  android.content.pm.SigningDetails getSigningDetails()\npublic  com.android.server.pm.PackageSetting setSigningDetails(android.content.pm.SigningDetails)\npublic  void copyPackageSetting(com.android.server.pm.PackageSetting)\n @com.android.internal.annotations.VisibleForTesting com.android.server.pm.pkg.PackageUserStateImpl modifyUserState(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateInternal readUserState(int)\n  void setEnabled(int,int,java.lang.String)\n  int getEnabled(int)\n  java.lang.String getLastDisabledAppCaller(int)\n  void setInstalled(boolean,int)\n  boolean getInstalled(int)\n  int getInstallReason(int)\n  void setInstallReason(int,int)\n  int getUninstallReason(int)\n  void setUninstallReason(int,int)\n  boolean setOverlayPaths(android.content.pm.overlay.OverlayPaths,int)\n @android.annotation.NonNull android.content.pm.overlay.OverlayPaths getOverlayPaths(int)\n  boolean setOverlayPathsForLibrary(java.lang.String,android.content.pm.overlay.OverlayPaths,int)\n @android.annotation.NonNull java.util.Map<java.lang.String,android.content.pm.overlay.OverlayPaths> getOverlayPathsForLibrary(int)\n  boolean isAnyInstalled(int[])\n  int[] queryInstalledUsers(int[],boolean)\n  long getCeDataInode(int)\n  void setCeDataInode(long,int)\n  boolean getStopped(int)\n  void setStopped(boolean,int)\n  boolean getNotLaunched(int)\n  void setNotLaunched(boolean,int)\n  boolean getHidden(int)\n  void setHidden(boolean,int)\n  int getDistractionFlags(int)\n  void setDistractionFlags(int,int)\n  boolean getSuspended(int)\n  boolean addOrUpdateSuspension(java.lang.String,android.content.pm.SuspendDialogInfo,android.os.PersistableBundle,android.os.PersistableBundle,int)\n  boolean removeSuspension(java.lang.String,int)\n  void removeSuspension(java.util.function.Predicate<java.lang.String>,int)\npublic  boolean getInstantApp(int)\n  void setInstantApp(boolean,int)\n  boolean getVirtualPreload(int)\n  void setVirtualPreload(boolean,int)\n  void setUserState(int,long,int,boolean,boolean,boolean,boolean,int,boolean,android.util.ArrayMap<java.lang.String,com.android.server.pm.pkg.SuspendParams>,boolean,boolean,java.lang.String,android.util.ArraySet<java.lang.String>,android.util.ArraySet<java.lang.String>,int,int,java.lang.String,java.lang.String)\n  void setUserState(int,com.android.server.pm.pkg.PackageUserStateInternal)\n  android.util.ArraySet<java.lang.String> getEnabledComponents(int)\n  android.util.ArraySet<java.lang.String> getDisabledComponents(int)\n  void setEnabledComponents(android.util.ArraySet<java.lang.String>,int)\n  void setDisabledComponents(android.util.ArraySet<java.lang.String>,int)\n  void setEnabledComponentsCopy(android.util.ArraySet<java.lang.String>,int)\n  void setDisabledComponentsCopy(android.util.ArraySet<java.lang.String>,int)\n  com.android.server.pm.pkg.PackageUserStateImpl modifyUserStateComponents(int,boolean,boolean)\n  void addDisabledComponent(java.lang.String,int)\n  void addEnabledComponent(java.lang.String,int)\n  boolean enableComponentLPw(java.lang.String,int)\n  boolean disableComponentLPw(java.lang.String,int)\n  boolean restoreComponentLPw(java.lang.String,int)\n  int getCurrentEnabledStateLPr(java.lang.String,int)\n  void removeUser(int)\npublic  int[] getNotInstalledUserIds()\n  void writePackageUserPermissionsProto(android.util.proto.ProtoOutputStream,long,java.util.List<android.content.pm.UserInfo>,com.android.server.pm.permission.LegacyPermissionDataProvider)\nprotected  void writeUsersInfoToProto(android.util.proto.ProtoOutputStream,long)\n  void setHarmfulAppWarning(int,java.lang.String)\n  java.lang.String getHarmfulAppWarning(int)\n  com.android.server.pm.PackageSetting setPath(java.io.File)\npublic @com.android.internal.annotations.VisibleForTesting boolean overrideNonLocalizedLabelAndIcon(android.content.ComponentName,java.lang.String,java.lang.Integer,int)\npublic  void resetOverrideComponentLabelIcon(int)\npublic  void setSplashScreenTheme(int,java.lang.String)\npublic @android.annotation.Nullable java.lang.String getSplashScreenTheme(int)\npublic  boolean isLoading()\npublic  com.android.server.pm.PackageSetting setLoadingProgress(float)\npublic @android.annotation.NonNull @java.lang.Override long getVersionCode()\npublic @android.annotation.Nullable @java.lang.Override java.util.Map<java.lang.String,java.util.Set<java.lang.String>> getMimeGroups()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String getPackageName()\npublic @android.annotation.Nullable @java.lang.Override com.android.server.pm.pkg.AndroidPackageApi getAndroidPackage()\npublic @android.annotation.Nullable @java.lang.Override java.lang.Integer getSharedUserId()\npublic @android.annotation.NonNull android.content.pm.SigningInfo getSigningInfo()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String[] getUsesStaticLibraries()\npublic @android.annotation.NonNull @java.lang.Override long[] getUsesStaticLibrariesVersions()\npublic @android.annotation.NonNull @java.lang.Override java.util.List<android.content.pm.SharedLibraryInfo> getUsesLibraryInfos()\npublic @android.annotation.NonNull @java.lang.Override java.util.List<java.lang.String> getUsesLibraryFiles()\npublic @java.lang.Override boolean isHiddenUntilInstalled()\npublic @android.annotation.NonNull @java.lang.Override long[] getLastPackageUsageTime()\npublic @java.lang.Override boolean isUpdatedSystemApp()\npublic  com.android.server.pm.PackageSetting setDomainSetId(java.util.UUID)\npublic  com.android.server.pm.PackageSetting setSharedUser(com.android.server.pm.SharedUserSetting)\npublic  com.android.server.pm.PackageSetting setCategoryOverride(int)\npublic  com.android.server.pm.PackageSetting setLegacyNativeLibraryPath(java.lang.String)\npublic  com.android.server.pm.PackageSetting setMimeGroups(java.util.Map<java.lang.String,java.util.Set<java.lang.String>>)\npublic  com.android.server.pm.PackageSetting setOldCodePaths(java.util.Set<java.lang.String>)\npublic  com.android.server.pm.PackageSetting setUsesStaticLibraries(java.lang.String[])\npublic  com.android.server.pm.PackageSetting setUsesStaticLibrariesVersions(long[])\npublic @android.annotation.NonNull @java.lang.Override com.android.server.pm.pkg.PackageStateUnserialized getTransientState()\npublic @android.annotation.NonNull android.util.SparseArray<? extends PackageUserStateInternal> getUserStates()\nclass PackageSetting extends com.android.server.pm.SettingBase implements [com.android.server.pm.pkg.PackageStateInternal]\n@com.android.internal.util.DataClass(genGetters=true, genConstructor=false, genSetters=false, genBuilder=false)")
+            inputSignatures = "private  int sharedUserId\nprivate @android.annotation.Nullable java.util.Map<java.lang.String,java.util.Set<java.lang.String>> mimeGroups\nprivate @java.lang.Deprecated @android.annotation.Nullable java.util.Set<java.lang.String> mOldCodePaths\nprivate @android.annotation.Nullable java.lang.String[] usesSdkLibraries\nprivate @android.annotation.Nullable long[] usesSdkLibrariesVersionsMajor\nprivate @android.annotation.Nullable java.lang.String[] usesStaticLibraries\nprivate @android.annotation.Nullable long[] usesStaticLibrariesVersions\nprivate @android.annotation.Nullable @java.lang.Deprecated java.lang.String legacyNativeLibraryPath\nprivate @android.annotation.NonNull java.lang.String mName\nprivate @android.annotation.Nullable java.lang.String mRealName\nprivate  int mAppId\nprivate @android.annotation.Nullable com.android.server.pm.parsing.pkg.AndroidPackage pkg\nprivate @android.annotation.Nullable com.android.server.pm.SharedUserSetting sharedUser\nprivate @android.annotation.NonNull java.io.File mPath\nprivate @android.annotation.NonNull java.lang.String mPathString\nprivate  float mLoadingProgress\nprivate @android.annotation.Nullable java.lang.String mPrimaryCpuAbi\nprivate @android.annotation.Nullable java.lang.String mSecondaryCpuAbi\nprivate @android.annotation.Nullable java.lang.String mCpuAbiOverride\nprivate  long mLastModifiedTime\nprivate  long lastUpdateTime\nprivate  long versionCode\nprivate @android.annotation.NonNull com.android.server.pm.PackageSignatures signatures\nprivate  boolean installPermissionsFixed\nprivate @android.annotation.NonNull com.android.server.pm.PackageKeySetData keySetData\nprivate final @android.annotation.NonNull android.util.SparseArray<com.android.server.pm.pkg.PackageUserStateImpl> mUserStates\nprivate @android.annotation.NonNull com.android.server.pm.InstallSource installSource\nprivate @android.annotation.Nullable java.lang.String volumeUuid\nprivate  int categoryOverride\nprivate  boolean updateAvailable\nprivate  boolean forceQueryableOverride\nprivate @android.annotation.NonNull com.android.server.pm.pkg.PackageStateUnserialized pkgState\nprivate @android.annotation.NonNull java.util.UUID mDomainSetId\nprivate final @android.annotation.NonNull com.android.server.utils.SnapshotCache<com.android.server.pm.PackageSetting> mSnapshot\nprivate  com.android.server.utils.SnapshotCache<com.android.server.pm.PackageSetting> makeCache()\npublic  com.android.server.pm.PackageSetting snapshot()\npublic  void dumpDebug(android.util.proto.ProtoOutputStream,long,java.util.List<android.content.pm.UserInfo>,com.android.server.pm.permission.LegacyPermissionDataProvider)\npublic  boolean isSharedUser()\npublic  com.android.server.pm.PackageSetting setAppId(int)\npublic  com.android.server.pm.PackageSetting setCpuAbiOverride(java.lang.String)\npublic  com.android.server.pm.PackageSetting setFirstInstallTimeFromReplaced(com.android.server.pm.pkg.PackageStateInternal,int[])\npublic  com.android.server.pm.PackageSetting setFirstInstallTime(long,int)\npublic  com.android.server.pm.PackageSetting setForceQueryableOverride(boolean)\npublic  com.android.server.pm.PackageSetting setInstallerPackageName(java.lang.String)\npublic  com.android.server.pm.PackageSetting setInstallSource(com.android.server.pm.InstallSource)\n  com.android.server.pm.PackageSetting removeInstallerPackage(java.lang.String)\npublic  com.android.server.pm.PackageSetting setIsOrphaned(boolean)\npublic  com.android.server.pm.PackageSetting setKeySetData(com.android.server.pm.PackageKeySetData)\npublic  com.android.server.pm.PackageSetting setLastModifiedTime(long)\npublic  com.android.server.pm.PackageSetting setLastUpdateTime(long)\npublic  com.android.server.pm.PackageSetting setLongVersionCode(long)\npublic  boolean setMimeGroup(java.lang.String,android.util.ArraySet<java.lang.String>)\npublic  com.android.server.pm.PackageSetting setPkg(com.android.server.pm.parsing.pkg.AndroidPackage)\npublic  com.android.server.pm.PackageSetting setPkgStateLibraryFiles(java.util.Collection<java.lang.String>)\npublic  com.android.server.pm.PackageSetting setPrimaryCpuAbi(java.lang.String)\npublic  com.android.server.pm.PackageSetting setSecondaryCpuAbi(java.lang.String)\npublic  com.android.server.pm.PackageSetting setSignatures(com.android.server.pm.PackageSignatures)\npublic  com.android.server.pm.PackageSetting setVolumeUuid(java.lang.String)\npublic @java.lang.Override boolean isExternalStorage()\npublic  com.android.server.pm.PackageSetting setUpdateAvailable(boolean)\npublic  int getSharedUserIdInt()\npublic @java.lang.Override java.lang.String toString()\nprotected  void copyMimeGroups(java.util.Map<java.lang.String,java.util.Set<java.lang.String>>)\npublic  void updateFrom(com.android.server.pm.PackageSetting)\n  com.android.server.pm.PackageSetting updateMimeGroups(java.util.Set<java.lang.String>)\npublic @java.lang.Deprecated @java.lang.Override com.android.server.pm.permission.LegacyPermissionState getLegacyPermissionState()\npublic  com.android.server.pm.PackageSetting setInstallPermissionsFixed(boolean)\npublic  boolean isPrivileged()\npublic  boolean isOem()\npublic  boolean isVendor()\npublic  boolean isProduct()\npublic @java.lang.Override boolean isRequiredForSystemUser()\npublic  boolean isSystemExt()\npublic  boolean isOdm()\npublic  boolean isSystem()\npublic  android.content.pm.SigningDetails getSigningDetails()\npublic  com.android.server.pm.PackageSetting setSigningDetails(android.content.pm.SigningDetails)\npublic  void copyPackageSetting(com.android.server.pm.PackageSetting)\n @com.android.internal.annotations.VisibleForTesting com.android.server.pm.pkg.PackageUserStateImpl modifyUserState(int)\npublic  com.android.server.pm.pkg.PackageUserStateImpl getOrCreateUserState(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateInternal readUserState(int)\n  void setEnabled(int,int,java.lang.String)\n  int getEnabled(int)\n  java.lang.String getLastDisabledAppCaller(int)\n  void setInstalled(boolean,int)\n  boolean getInstalled(int)\n  int getInstallReason(int)\n  void setInstallReason(int,int)\n  int getUninstallReason(int)\n  void setUninstallReason(int,int)\n  boolean setOverlayPaths(android.content.pm.overlay.OverlayPaths,int)\n @android.annotation.NonNull android.content.pm.overlay.OverlayPaths getOverlayPaths(int)\n  boolean setOverlayPathsForLibrary(java.lang.String,android.content.pm.overlay.OverlayPaths,int)\n @android.annotation.NonNull java.util.Map<java.lang.String,android.content.pm.overlay.OverlayPaths> getOverlayPathsForLibrary(int)\n  boolean isAnyInstalled(int[])\n  int[] queryInstalledUsers(int[],boolean)\n  long getCeDataInode(int)\n  void setCeDataInode(long,int)\n  boolean getStopped(int)\n  void setStopped(boolean,int)\n  boolean getNotLaunched(int)\n  void setNotLaunched(boolean,int)\n  boolean getHidden(int)\n  void setHidden(boolean,int)\n  int getDistractionFlags(int)\n  void setDistractionFlags(int,int)\n  boolean getSuspended(int)\n  boolean addOrUpdateSuspension(java.lang.String,android.content.pm.SuspendDialogInfo,android.os.PersistableBundle,android.os.PersistableBundle,int)\n  boolean removeSuspension(java.lang.String,int)\n  void removeSuspension(java.util.function.Predicate<java.lang.String>,int)\npublic  boolean getInstantApp(int)\n  void setInstantApp(boolean,int)\n  boolean getVirtualPreload(int)\n  void setVirtualPreload(boolean,int)\n  void setUserState(int,long,int,boolean,boolean,boolean,boolean,int,android.util.ArrayMap<java.lang.String,com.android.server.pm.pkg.SuspendParams>,boolean,boolean,java.lang.String,android.util.ArraySet<java.lang.String>,android.util.ArraySet<java.lang.String>,int,int,java.lang.String,java.lang.String,long)\n  void setUserState(int,com.android.server.pm.pkg.PackageUserStateInternal)\n  android.util.ArraySet<java.lang.String> getEnabledComponents(int)\n  android.util.ArraySet<java.lang.String> getDisabledComponents(int)\n  void setEnabledComponents(android.util.ArraySet<java.lang.String>,int)\n  void setDisabledComponents(android.util.ArraySet<java.lang.String>,int)\n  void setEnabledComponentsCopy(android.util.ArraySet<java.lang.String>,int)\n  void setDisabledComponentsCopy(android.util.ArraySet<java.lang.String>,int)\n  com.android.server.pm.pkg.PackageUserStateImpl modifyUserStateComponents(int,boolean,boolean)\n  void addDisabledComponent(java.lang.String,int)\n  void addEnabledComponent(java.lang.String,int)\n  boolean enableComponentLPw(java.lang.String,int)\n  boolean disableComponentLPw(java.lang.String,int)\n  boolean restoreComponentLPw(java.lang.String,int)\n  int getCurrentEnabledStateLPr(java.lang.String,int)\n  void removeUser(int)\npublic  int[] getNotInstalledUserIds()\n  void writePackageUserPermissionsProto(android.util.proto.ProtoOutputStream,long,java.util.List<android.content.pm.UserInfo>,com.android.server.pm.permission.LegacyPermissionDataProvider)\nprotected  void writeUsersInfoToProto(android.util.proto.ProtoOutputStream,long)\n  void setHarmfulAppWarning(int,java.lang.String)\n  java.lang.String getHarmfulAppWarning(int)\n  com.android.server.pm.PackageSetting setPath(java.io.File)\npublic @com.android.internal.annotations.VisibleForTesting boolean overrideNonLocalizedLabelAndIcon(android.content.ComponentName,java.lang.String,java.lang.Integer,int)\npublic  void resetOverrideComponentLabelIcon(int)\npublic  void setSplashScreenTheme(int,java.lang.String)\npublic @android.annotation.Nullable java.lang.String getSplashScreenTheme(int)\npublic  boolean isLoading()\npublic  com.android.server.pm.PackageSetting setLoadingProgress(float)\npublic @android.annotation.NonNull @java.lang.Override long getVersionCode()\npublic @android.annotation.Nullable @java.lang.Override java.util.Map<java.lang.String,java.util.Set<java.lang.String>> getMimeGroups()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String getPackageName()\npublic @android.annotation.Nullable @java.lang.Override com.android.server.pm.pkg.AndroidPackageApi getAndroidPackage()\npublic @android.annotation.Nullable @java.lang.Override java.lang.Integer getSharedUserId()\npublic @android.annotation.NonNull android.content.pm.SigningInfo getSigningInfo()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String[] getUsesSdkLibraries()\npublic @android.annotation.NonNull @java.lang.Override long[] getUsesSdkLibrariesVersionsMajor()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String[] getUsesStaticLibraries()\npublic @android.annotation.NonNull @java.lang.Override long[] getUsesStaticLibrariesVersions()\npublic @android.annotation.NonNull @java.lang.Override java.util.List<android.content.pm.SharedLibraryInfo> getUsesLibraryInfos()\npublic @android.annotation.NonNull @java.lang.Override java.util.List<java.lang.String> getUsesLibraryFiles()\npublic @java.lang.Override boolean isHiddenUntilInstalled()\npublic @android.annotation.NonNull @java.lang.Override long[] getLastPackageUsageTime()\npublic @java.lang.Override boolean isUpdatedSystemApp()\npublic  com.android.server.pm.PackageSetting setDomainSetId(java.util.UUID)\npublic  com.android.server.pm.PackageSetting setSharedUser(com.android.server.pm.SharedUserSetting)\npublic  com.android.server.pm.PackageSetting setCategoryOverride(int)\npublic  com.android.server.pm.PackageSetting setLegacyNativeLibraryPath(java.lang.String)\npublic  com.android.server.pm.PackageSetting setMimeGroups(java.util.Map<java.lang.String,java.util.Set<java.lang.String>>)\npublic  com.android.server.pm.PackageSetting setOldCodePaths(java.util.Set<java.lang.String>)\npublic  com.android.server.pm.PackageSetting setUsesSdkLibraries(java.lang.String[])\npublic  com.android.server.pm.PackageSetting setUsesSdkLibrariesVersionsMajor(long[])\npublic  com.android.server.pm.PackageSetting setUsesStaticLibraries(java.lang.String[])\npublic  com.android.server.pm.PackageSetting setUsesStaticLibrariesVersions(long[])\npublic @android.annotation.NonNull @java.lang.Override com.android.server.pm.pkg.PackageStateUnserialized getTransientState()\npublic @android.annotation.NonNull android.util.SparseArray<? extends PackageUserStateInternal> getUserStates()\npublic  com.android.server.pm.PackageSetting addMimeTypes(java.lang.String,java.util.Set<java.lang.String>)\nclass PackageSetting extends com.android.server.pm.SettingBase implements [com.android.server.pm.pkg.PackageStateInternal]\n@com.android.internal.util.DataClass(genGetters=true, genConstructor=false, genSetters=false, genBuilder=false)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/services/core/java/com/android/server/pm/RemovePackageHelper.java b/services/core/java/com/android/server/pm/RemovePackageHelper.java
index 749495c..d60d019 100644
--- a/services/core/java/com/android/server/pm/RemovePackageHelper.java
+++ b/services/core/java/com/android/server/pm/RemovePackageHelper.java
@@ -29,10 +29,7 @@
 
 import android.annotation.NonNull;
 import android.content.pm.PackageManager;
-import android.content.pm.SharedLibraryInfo;
-import android.content.pm.VersionedPackage;
 import android.content.pm.parsing.component.ParsedInstrumentation;
-import android.os.Process;
 import android.os.UserHandle;
 import android.os.incremental.IncrementalManager;
 import android.util.Log;
@@ -46,7 +43,6 @@
 import com.android.server.pm.parsing.pkg.PackageImpl;
 import com.android.server.pm.permission.PermissionManagerServiceInternal;
 import com.android.server.pm.pkg.PackageStateInternal;
-import com.android.server.utils.WatchedLongSparseArray;
 
 import java.io.File;
 import java.util.Collections;
@@ -62,6 +58,7 @@
     private final Installer mInstaller;
     private final UserManagerInternal mUserManagerInternal;
     private final PermissionManagerServiceInternal mPermissionManager;
+    private final SharedLibrariesImpl mSharedLibraries;
     private final AppDataHelper mAppDataHelper;
 
     // TODO(b/198166813): remove PMS dependency
@@ -71,6 +68,7 @@
         mInstaller = mPm.mInjector.getInstaller();
         mUserManagerInternal = mPm.mInjector.getUserManagerInternal();
         mPermissionManager = mPm.mInjector.getPermissionManagerServiceInternal();
+        mSharedLibraries = mPm.mInjector.getSharedLibrariesImpl();
         mAppDataHelper = appDataHelper;
     }
 
@@ -174,7 +172,7 @@
             final int libraryNamesSize = pkg.getLibraryNames().size();
             for (i = 0; i < libraryNamesSize; i++) {
                 String name = pkg.getLibraryNames().get(i);
-                if (removeSharedLibraryLPw(name, 0)) {
+                if (mSharedLibraries.removeSharedLibraryLPw(name, 0)) {
                     if (DEBUG_REMOVE && chatty) {
                         if (r == null) {
                             r = new StringBuilder(256);
@@ -191,7 +189,8 @@
 
         // Any package can hold SDK or static shared libraries.
         if (pkg.getSdkLibName() != null) {
-            if (removeSharedLibraryLPw(pkg.getSdkLibName(), pkg.getSdkLibVersionMajor())) {
+            if (mSharedLibraries.removeSharedLibraryLPw(
+                    pkg.getSdkLibName(), pkg.getSdkLibVersionMajor())) {
                 if (DEBUG_REMOVE && chatty) {
                     if (r == null) {
                         r = new StringBuilder(256);
@@ -203,7 +202,7 @@
             }
         }
         if (pkg.getStaticSharedLibName() != null) {
-            if (removeSharedLibraryLPw(pkg.getStaticSharedLibName(),
+            if (mSharedLibraries.removeSharedLibraryLPw(pkg.getStaticSharedLibName(),
                     pkg.getStaticSharedLibVersion())) {
                 if (DEBUG_REMOVE && chatty) {
                     if (r == null) {
@@ -221,44 +220,6 @@
         }
     }
 
-    private boolean removeSharedLibraryLPw(String name, long version) {
-        WatchedLongSparseArray<SharedLibraryInfo> versionedLib = mPm.mSharedLibraries.get(name);
-        if (versionedLib == null) {
-            return false;
-        }
-        final int libIdx = versionedLib.indexOfKey(version);
-        if (libIdx < 0) {
-            return false;
-        }
-        SharedLibraryInfo libraryInfo = versionedLib.valueAt(libIdx);
-
-        // Remove the shared library overlays from its dependent packages.
-        for (int currentUserId : UserManagerService.getInstance().getUserIds()) {
-            final List<VersionedPackage> dependents = mPm.getPackagesUsingSharedLibrary(
-                    libraryInfo, 0, Process.SYSTEM_UID, currentUserId);
-            if (dependents == null) {
-                continue;
-            }
-            for (VersionedPackage dependentPackage : dependents) {
-                final PackageSetting ps = mPm.mSettings.getPackageLPr(
-                        dependentPackage.getPackageName());
-                if (ps != null) {
-                    ps.setOverlayPathsForLibrary(libraryInfo.getName(), null, currentUserId);
-                }
-            }
-        }
-
-        versionedLib.remove(version);
-        if (versionedLib.size() <= 0) {
-            mPm.mSharedLibraries.remove(name);
-            if (libraryInfo.getType() == SharedLibraryInfo.TYPE_STATIC) {
-                mPm.mStaticLibsByDeclaringPackage.remove(libraryInfo.getDeclaringPackage()
-                        .getPackageName());
-            }
-        }
-        return true;
-    }
-
     /*
      * This method deletes the package from internal data structures. If the DELETE_KEEP_DATA
      * flag is not set, the data directory is removed as well.
diff --git a/services/core/java/com/android/server/pm/SELinuxMMAC.java b/services/core/java/com/android/server/pm/SELinuxMMAC.java
index 9f3d190..19f180f 100644
--- a/services/core/java/com/android/server/pm/SELinuxMMAC.java
+++ b/services/core/java/com/android/server/pm/SELinuxMMAC.java
@@ -125,16 +125,10 @@
         }
 
         // Vendor mac permissions.
-        // The filename has been renamed from nonplat_mac_permissions to
-        // vendor_mac_permissions. Either of them should exist.
         final File vendorMacPermission = new File(
             Environment.getVendorDirectory(), "/etc/selinux/vendor_mac_permissions.xml");
         if (vendorMacPermission.exists()) {
             sMacPermissions.add(vendorMacPermission);
-        } else {
-            // For backward compatibility.
-            sMacPermissions.add(new File(Environment.getVendorDirectory(),
-                                         "/etc/selinux/nonplat_mac_permissions.xml"));
         }
 
         // ODM mac permissions (optional).
diff --git a/services/core/java/com/android/server/pm/ScanPackageUtils.java b/services/core/java/com/android/server/pm/ScanPackageUtils.java
index 378c9e0..6d2ec0d 100644
--- a/services/core/java/com/android/server/pm/ScanPackageUtils.java
+++ b/services/core/java/com/android/server/pm/ScanPackageUtils.java
@@ -84,6 +84,7 @@
 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.pkg.PackageStateUtils;
 
 import dalvik.system.VMRuntime;
 
@@ -410,16 +411,19 @@
 
         // Take care of first install / last update times.
         final long scanFileTime = getLastModifiedTime(parsedPackage);
+        final long existingFirstInstallTime = userId == UserHandle.USER_ALL
+                ? PackageStateUtils.getEarliestFirstInstallTime(pkgSetting.getUserStates())
+                : pkgSetting.readUserState(userId).getFirstInstallTime();
         if (currentTime != 0) {
-            if (pkgSetting.getFirstInstallTime() == 0) {
-                pkgSetting.setFirstInstallTime(currentTime)
+            if (existingFirstInstallTime == 0) {
+                pkgSetting.setFirstInstallTime(currentTime, userId)
                         .setLastUpdateTime(currentTime);
             } else if ((scanFlags & SCAN_UPDATE_TIME) != 0) {
                 pkgSetting.setLastUpdateTime(currentTime);
             }
-        } else if (pkgSetting.getFirstInstallTime() == 0) {
-            // We need *something*.  Take time time stamp of the file.
-            pkgSetting.setFirstInstallTime(scanFileTime)
+        } else if (existingFirstInstallTime == 0) {
+            // We need *something*.  Take time stamp of the file.
+            pkgSetting.setFirstInstallTime(scanFileTime, userId)
                     .setLastUpdateTime(scanFileTime);
         } else if ((parseFlags & ParsingPackageUtils.PARSE_IS_SYSTEM_DIR) != 0) {
             if (scanFileTime != pkgSetting.getLastModifiedTime()) {
diff --git a/services/core/java/com/android/server/pm/SettingBase.java b/services/core/java/com/android/server/pm/SettingBase.java
index ed85ff9..4345d51 100644
--- a/services/core/java/com/android/server/pm/SettingBase.java
+++ b/services/core/java/com/android/server/pm/SettingBase.java
@@ -22,6 +22,7 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.pm.permission.LegacyPermissionState;
+import com.android.server.pm.pkg.mutate.PackageStateMutator;
 import com.android.server.utils.Snappable;
 import com.android.server.utils.Watchable;
 import com.android.server.utils.WatchableImpl;
@@ -88,6 +89,7 @@
      * Notify listeners that this object has changed.
      */
     protected void onChanged() {
+        PackageStateMutator.onPackageStateChanged();
         dispatchChange(this);
     }
 
@@ -122,7 +124,7 @@
         return mLegacyPermissionsState;
     }
 
-    SettingBase setFlags(int pkgFlags) {
+    public SettingBase setFlags(int pkgFlags) {
         this.mPkgFlags = pkgFlags
                 & (ApplicationInfo.FLAG_SYSTEM
                         | ApplicationInfo.FLAG_EXTERNAL_STORAGE
@@ -131,7 +133,7 @@
         return this;
     }
 
-    SettingBase setPrivateFlags(int pkgPrivateFlags) {
+    public SettingBase setPrivateFlags(int pkgPrivateFlags) {
         this.mPkgPrivateFlags = pkgPrivateFlags
                 & (ApplicationInfo.PRIVATE_FLAG_PRIVILEGED
                 | ApplicationInfo.PRIVATE_FLAG_OEM
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index b1ce6a2..21df5a9 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -114,6 +114,7 @@
 import com.android.server.pm.permission.LegacyPermissionSettings;
 import com.android.server.pm.permission.LegacyPermissionState;
 import com.android.server.pm.permission.LegacyPermissionState.PermissionState;
+import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.PackageUserState;
 import com.android.server.pm.pkg.PackageUserStateInternal;
 import com.android.server.pm.pkg.SuspendParams;
@@ -162,6 +163,7 @@
 import java.util.Objects;
 import java.util.Set;
 import java.util.UUID;
+import java.util.function.Consumer;
 
 /**
  * Holds information about dynamic settings.
@@ -257,7 +259,7 @@
         public static final int SIGNATURE_MALFORMED_RECOVER = 3;
     }
 
-    private static final boolean DEBUG_STOPPED = false;
+    static final boolean DEBUG_STOPPED = false;
     private static final boolean DEBUG_MU = false;
     private static final boolean DEBUG_KERNEL = false;
     private static final boolean DEBUG_PARSER = false;
@@ -353,6 +355,7 @@
     private static final String ATTR_SDK_VERSION = "sdkVersion";
     private static final String ATTR_DATABASE_VERSION = "databaseVersion";
     private static final String ATTR_VALUE = "value";
+    private static final String ATTR_FIRST_INSTALL_TIME = "first-install-time";
 
     private final PackageManagerTracedLock mLock;
 
@@ -625,7 +628,15 @@
         mOtherAppIds = new WatchedSparseArray<>();
         mPermissions = new LegacyPermissionSettings(lock);
         mRuntimePermissionsPersistence = new RuntimePermissionPersistence(
-                runtimePermissionsPersistence);
+                runtimePermissionsPersistence, new Consumer<Integer>() {
+            @Override
+            public void accept(Integer userId) {
+                synchronized (mLock) {
+                    mRuntimePermissionsPersistence.writeStateForUserSync(userId,
+                            mPermissionDataProvider, mPackages, mSharedUsers);
+                }
+            }
+        });
         mPermissionDataProvider = permissionDataProvider;
 
         mSystemDir = new File(dataDir, "system");
@@ -989,7 +1000,6 @@
                                 true /*notLaunched*/,
                                 false /*hidden*/,
                                 0 /*distractionFlags*/,
-                                false /*suspended*/,
                                 null /*suspendParams*/,
                                 instantApp,
                                 virtualPreload,
@@ -998,8 +1008,9 @@
                                 null /*disabledComponents*/,
                                 PackageManager.INSTALL_REASON_UNKNOWN,
                                 PackageManager.UNINSTALL_REASON_UNKNOWN,
-                                null, /*harmfulAppWarning*/
-                                null /*splashscreenTheme*/
+                                null /*harmfulAppWarning*/,
+                                null /*splashscreenTheme*/,
+                                0 /*firstInstallTime*/
                         );
                     }
                 }
@@ -1423,7 +1434,7 @@
 
     void writeAllRuntimePermissionsLPr() {
         for (int userId : UserManagerService.getInstance().getUserIds()) {
-            mRuntimePermissionsPersistence.writeStateForUserAsyncLPr(userId);
+            mRuntimePermissionsPersistence.writeStateForUserAsync(userId);
         }
     }
 
@@ -1432,15 +1443,15 @@
     }
 
     void updateRuntimePermissionsFingerprintLPr(@UserIdInt int userId) {
-        mRuntimePermissionsPersistence.updateRuntimePermissionsFingerprintLPr(userId);
+        mRuntimePermissionsPersistence.updateRuntimePermissionsFingerprint(userId);
     }
 
     int getDefaultRuntimePermissionsVersionLPr(int userId) {
-        return mRuntimePermissionsPersistence.getVersionLPr(userId);
+        return mRuntimePermissionsPersistence.getVersion(userId);
     }
 
     void setDefaultRuntimePermissionsVersionLPr(int version, int userId) {
-        mRuntimePermissionsPersistence.setVersionLPr(version, userId);
+        mRuntimePermissionsPersistence.setVersion(version, userId);
     }
 
     void setPermissionControllerVersion(long version) {
@@ -1602,7 +1613,8 @@
         }
     }
 
-    void readPackageRestrictionsLPr(int userId) {
+    void readPackageRestrictionsLPr(int userId,
+            @NonNull ArrayMap<String, Long> origFirstInstallTimes) {
         if (DEBUG_MU) {
             Log.i(TAG, "Reading package restrictions for user=" + userId);
         }
@@ -1646,7 +1658,6 @@
                                 false /*notLaunched*/,
                                 false /*hidden*/,
                                 0 /*distractionFlags*/,
-                                false /*suspended*/,
                                 null /*suspendParams*/,
                                 false /*instantApp*/,
                                 false /*virtualPreload*/,
@@ -1656,7 +1667,9 @@
                                 PackageManager.INSTALL_REASON_UNKNOWN,
                                 PackageManager.UNINSTALL_REASON_UNKNOWN,
                                 null /*harmfulAppWarning*/,
-                                null /* splashScreenTheme*/);
+                                null /* splashScreenTheme*/,
+                                0 /*firstInstallTime*/
+                        );
                     }
                     return;
                 }
@@ -1746,6 +1759,8 @@
                             PackageManager.UNINSTALL_REASON_UNKNOWN);
                     final String splashScreenTheme = parser.getAttributeValue(null,
                             ATTR_SPLASH_SCREEN_THEME);
+                    final long firstInstallTime = parser.getAttributeLongHex(null,
+                            ATTR_FIRST_INSTALL_TIME, 0);
 
                     ArraySet<String> enabledComponents = null;
                     ArraySet<String> disabledComponents = null;
@@ -1816,10 +1831,11 @@
                         setBlockUninstallLPw(userId, name, true);
                     }
                     ps.setUserState(userId, ceDataInode, enabled, installed, stopped, notLaunched,
-                            hidden, distractionFlags, suspended, suspendParamsMap,
-                            instantApp, virtualPreload, enabledCaller, enabledComponents,
-                            disabledComponents, installReason, uninstallReason, harmfulAppWarning,
-                            splashScreenTheme);
+                            hidden, distractionFlags, suspendParamsMap, instantApp, virtualPreload,
+                            enabledCaller, enabledComponents, disabledComponents, installReason,
+                            uninstallReason, harmfulAppWarning, splashScreenTheme,
+                            firstInstallTime != 0 ? firstInstallTime :
+                                    origFirstInstallTimes.getOrDefault(name, 0L));
 
                     mDomainVerificationManager.setLegacyUserState(name, userId, verifState);
                 } else if (tagName.equals("preferred-activities")) {
@@ -2072,6 +2088,8 @@
                     serializer.attributeInt(null, ATTR_INSTALL_REASON,
                             ustate.getInstallReason());
                 }
+                serializer.attributeLongHex(null, ATTR_FIRST_INSTALL_TIME,
+                        ustate.getFirstInstallTime());
                 if (ustate.getUninstallReason() != PackageManager.UNINSTALL_REASON_UNKNOWN) {
                     serializer.attributeInt(null, ATTR_UNINSTALL_REASON,
                             ustate.getUninstallReason());
@@ -2739,7 +2757,6 @@
         }
         serializer.attribute(null, "codePath", pkg.getPathString());
         serializer.attributeLongHex(null, "ft", pkg.getLastModifiedTime());
-        serializer.attributeLongHex(null, "it", pkg.getFirstInstallTime());
         serializer.attributeLongHex(null, "ut", pkg.getLastUpdateTime());
         serializer.attributeLong(null, "version", pkg.getVersionCode());
         if (pkg.getLegacyNativeLibraryPath() != null) {
@@ -2796,7 +2813,6 @@
         serializer.attributeInt(null, "publicFlags", pkg.getFlags());
         serializer.attributeInt(null, "privateFlags", pkg.getPrivateFlags());
         serializer.attributeLongHex(null, "ft", pkg.getLastModifiedTime());
-        serializer.attributeLongHex(null, "it", pkg.getFirstInstallTime());
         serializer.attributeLongHex(null, "ut", pkg.getLastUpdateTime());
         serializer.attributeLong(null, "version", pkg.getVersionCode());
         if (pkg.getSharedUser() == null) {
@@ -2918,6 +2934,11 @@
         mKeySetRefs.clear();
         mInstallerPackages.clear();
 
+        // If any user state doesn't have a first install time, e.g., after an OTA,
+        // use the pre OTA firstInstallTime timestamp. This is because we migrated from per package
+        // firstInstallTime to per user-state. Without this, OTA can cause this info to be lost.
+        final ArrayMap<String, Long> originalFirstInstallTimes = new ArrayMap<>();
+
         try {
             if (str == null) {
                 if (!mSettingsFilename.exists()) {
@@ -2958,7 +2979,7 @@
 
                 String tagName = parser.getName();
                 if (tagName.equals("package")) {
-                    readPackageLPw(parser, users);
+                    readPackageLPw(parser, users, originalFirstInstallTimes);
                 } else if (tagName.equals("permissions")) {
                     mPermissions.readPermissions(parser);
                 } else if (tagName.equals("permission-trees")) {
@@ -3095,12 +3116,13 @@
             writePackageRestrictionsLPr(UserHandle.USER_SYSTEM);
         } else {
             for (UserInfo user : users) {
-                readPackageRestrictionsLPr(user.id);
+                readPackageRestrictionsLPr(user.id, originalFirstInstallTimes);
             }
         }
 
         for (UserInfo user : users) {
-            mRuntimePermissionsPersistence.readStateForUserSyncLPr(user.id);
+            mRuntimePermissionsPersistence.readStateForUserSync(user.id, getInternalVersion(),
+                    mPackages, mSharedUsers, getUserRuntimePermissionsFile(user.id));
         }
 
         /*
@@ -3124,7 +3146,8 @@
     }
 
     void readPermissionStateForUserSyncLPr(@UserIdInt int userId) {
-        mRuntimePermissionsPersistence.readStateForUserSyncLPr(userId);
+        mRuntimePermissionsPersistence.readStateForUserSync(userId, getInternalVersion(),
+                mPackages, mSharedUsers, getUserRuntimePermissionsFile(userId));
     }
 
     void applyDefaultPreferredAppsLPw(int userId) {
@@ -3523,7 +3546,6 @@
             timeStamp = parser.getAttributeLong(null, "ts", 0);
         }
         ps.setLastModifiedTime(timeStamp);
-        ps.setFirstInstallTime(parser.getAttributeLongHex(null, "it", 0));
         ps.setLastUpdateTime(parser.getAttributeLongHex(null, "ut", 0));
         ps.setAppId(parser.getAttributeInt(null, "userId", 0));
         if (ps.getAppId() <= 0) {
@@ -3561,7 +3583,8 @@
     private static int PRE_M_APP_INFO_FLAG_CANT_SAVE_STATE = 1<<28;
     private static int PRE_M_APP_INFO_FLAG_PRIVILEGED = 1<<30;
 
-    private void readPackageLPw(TypedXmlPullParser parser, List<UserInfo> users)
+    private void readPackageLPw(TypedXmlPullParser parser, List<UserInfo> users,
+            ArrayMap<String, Long> originalFirstInstallTimes)
             throws XmlPullParserException, IOException {
         String name = null;
         String realName = null;
@@ -3717,7 +3740,6 @@
                             + parser.getPositionDescription());
                 } else {
                     packageSetting.setLastModifiedTime(timeStamp);
-                    packageSetting.setFirstInstallTime(firstInstallTime);
                     packageSetting.setLastUpdateTime(lastUpdateTime);
                 }
             } else if (sharedUserId != 0) {
@@ -3732,7 +3754,6 @@
                             null /* usesStaticLibraryVersions */,
                             null /* mimeGroups */, domainSetId);
                     packageSetting.setLastModifiedTime(timeStamp);
-                    packageSetting.setFirstInstallTime(firstInstallTime);
                     packageSetting.setLastUpdateTime(lastUpdateTime);
                     mPendingPackages.add(packageSetting);
                     if (PackageManagerService.DEBUG_SETTINGS)
@@ -3867,6 +3888,9 @@
                     XmlUtils.skipCurrentTag(parser);
                 }
             }
+            if (firstInstallTime != 0) {
+                originalFirstInstallTimes.put(packageSetting.getPackageName(), firstInstallTime);
+            }
         } else {
             XmlUtils.skipCurrentTag(parser);
         }
@@ -4120,7 +4144,7 @@
         file.delete();
         removeCrossProfileIntentFiltersLPw(userId);
 
-        mRuntimePermissionsPersistence.onUserRemovedLPw(userId);
+        mRuntimePermissionsPersistence.onUserRemoved(userId);
         mDomainVerificationManager.clearUser(userId);
 
         writePackageListLPr();
@@ -4462,8 +4486,6 @@
             pw.print(",");
             pw.print(ps.getVersionCode());
             pw.print(",");
-            pw.print(ps.getFirstInstallTime());
-            pw.print(",");
             pw.print(ps.getLastUpdateTime());
             pw.print(",");
             pw.print(ps.getInstallSource().installerPackageName != null
@@ -4485,27 +4507,30 @@
                 }
             }
             for (UserInfo user : users) {
+                final PackageUserStateInternal userState = ps.getUserStateOrDefault(user.id);
                 pw.print(checkinTag);
                 pw.print("-");
                 pw.print("usr");
                 pw.print(",");
                 pw.print(user.id);
                 pw.print(",");
-                pw.print(ps.getInstalled(user.id) ? "I" : "i");
-                pw.print(ps.getHidden(user.id) ? "B" : "b");
-                pw.print(ps.getSuspended(user.id) ? "SU" : "su");
-                pw.print(ps.getStopped(user.id) ? "S" : "s");
-                pw.print(ps.getNotLaunched(user.id) ? "l" : "L");
-                pw.print(ps.getInstantApp(user.id) ? "IA" : "ia");
-                pw.print(ps.getVirtualPreload(user.id) ? "VPI" : "vpi");
-                String harmfulAppWarning = ps.getHarmfulAppWarning(user.id);
+                pw.print(userState.isInstalled() ? "I" : "i");
+                pw.print(userState.isHidden() ? "B" : "b");
+                pw.print(userState.isSuspended() ? "SU" : "su");
+                pw.print(userState.isStopped() ? "S" : "s");
+                pw.print(userState.isNotLaunched() ? "l" : "L");
+                pw.print(userState.isInstantApp() ? "IA" : "ia");
+                pw.print(userState.isVirtualPreload() ? "VPI" : "vpi");
+                String harmfulAppWarning = userState.getHarmfulAppWarning();
                 pw.print(harmfulAppWarning != null ? "HA" : "ha");
                 pw.print(",");
-                pw.print(ps.getEnabled(user.id));
-                String lastDisabledAppCaller = ps.getLastDisabledAppCaller(user.id);
+                pw.print(userState.getEnabledState());
+                String lastDisabledAppCaller = userState.getLastDisableAppCaller();
                 pw.print(",");
                 pw.print(lastDisabledAppCaller != null ? lastDisabledAppCaller : "?");
                 pw.print(",");
+                pw.print(ps.readUserState(user.id).getFirstInstallTime());
+                pw.print(",");
                 pw.println();
             }
             return;
@@ -4736,9 +4761,6 @@
         pw.print(prefix); pw.print("  timeStamp=");
             date.setTime(ps.getLastModifiedTime());
             pw.println(sdf.format(date));
-        pw.print(prefix); pw.print("  firstInstallTime=");
-            date.setTime(ps.getFirstInstallTime());
-            pw.println(sdf.format(date));
         pw.print(prefix); pw.print("  lastUpdateTime=");
             date.setTime(ps.getLastUpdateTime());
             pw.println(sdf.format(date));
@@ -4819,48 +4841,53 @@
         }
 
         for (UserInfo user : users) {
+            final PackageUserStateInternal userState = ps.getUserStateOrDefault(user.id);
             pw.print(prefix); pw.print("  User "); pw.print(user.id); pw.print(": ");
             pw.print("ceDataInode=");
-            pw.print(ps.getCeDataInode(user.id));
+            pw.print(userState.getCeDataInode());
             pw.print(" installed=");
-            pw.print(ps.getInstalled(user.id));
+            pw.print(userState.isInstalled());
             pw.print(" hidden=");
-            pw.print(ps.getHidden(user.id));
+            pw.print(userState.isHidden());
             pw.print(" suspended=");
-            pw.print(ps.getSuspended(user.id));
+            pw.print(userState.isSuspended());
             pw.print(" distractionFlags=");
-            pw.print(ps.getDistractionFlags(user.id));
+            pw.print(userState.getDistractionFlags());
             pw.print(" stopped=");
-            pw.print(ps.getStopped(user.id));
+            pw.print(userState.isStopped());
             pw.print(" notLaunched=");
-            pw.print(ps.getNotLaunched(user.id));
+            pw.print(userState.isNotLaunched());
             pw.print(" enabled=");
-            pw.print(ps.getEnabled(user.id));
+            pw.print(userState.getEnabledState());
             pw.print(" instant=");
-            pw.print(ps.getInstantApp(user.id));
+            pw.print(userState.isInstantApp());
             pw.print(" virtual=");
-            pw.print(ps.getVirtualPreload(user.id));
+            pw.println(userState.isVirtualPreload());
             pw.print(" installReason=");
-            pw.println(ps.getInstallReason(user.id));
+            pw.println(userState.getInstallReason());
 
-            if (ps.getSuspended(user.id)) {
+            final PackageUserStateInternal pus = ps.readUserState(user.id);
+            pw.print(" firstInstallTime=");
+            date.setTime(pus.getFirstInstallTime());
+            pw.println(sdf.format(date));
+
+            if (userState.isSuspended()) {
                 pw.print(prefix);
                 pw.println("  Suspend params:");
-                final PackageUserStateInternal pus = ps.readUserState(user.id);
-                for (int i = 0; i < pus.getSuspendParams().size(); i++) {
+                for (int i = 0; i < userState.getSuspendParams().size(); i++) {
                     pw.print(prefix);
                     pw.print("    suspendingPackage=");
-                    pw.print(pus.getSuspendParams().keyAt(i));
-                    final SuspendParams params = pus.getSuspendParams().valueAt(i);
+                    pw.print(userState.getSuspendParams().keyAt(i));
+                    final SuspendParams params = userState.getSuspendParams().valueAt(i);
                     if (params != null) {
                         pw.print(" dialogInfo=");
-                        pw.print(params.dialogInfo);
+                        pw.print(params.getDialogInfo());
                     }
                     pw.println();
                 }
             }
 
-            final OverlayPaths overlayPaths = ps.getOverlayPaths(user.id);
+            final OverlayPaths overlayPaths = userState.getOverlayPaths();
             if (overlayPaths != null) {
                 if (!overlayPaths.getOverlayPaths().isEmpty()) {
                     pw.print(prefix);
@@ -4883,7 +4910,7 @@
             }
 
             final Map<String, OverlayPaths> sharedLibraryOverlayPaths =
-                    ps.getOverlayPathsForLibrary(user.id);
+                    userState.getSharedLibraryOverlayPaths();
             if (sharedLibraryOverlayPaths != null) {
                 for (Map.Entry<String, OverlayPaths> libOverlayPaths :
                         sharedLibraryOverlayPaths.entrySet()) {
@@ -4916,7 +4943,7 @@
                 }
             }
 
-            String lastDisabledAppCaller = ps.getLastDisabledAppCaller(user.id);
+            String lastDisabledAppCaller = userState.getLastDisableAppCaller();
             if (lastDisabledAppCaller != null) {
                 pw.print(prefix); pw.print("    lastDisabledCaller: ");
                         pw.println(lastDisabledAppCaller);
@@ -4929,21 +4956,21 @@
                         .getPermissionStates(user.id), dumpAll);
             }
 
-            String harmfulAppWarning = ps.getHarmfulAppWarning(user.id);
+            String harmfulAppWarning = userState.getHarmfulAppWarning();
             if (harmfulAppWarning != null) {
                 pw.print(prefix); pw.print("      harmfulAppWarning: ");
                 pw.println(harmfulAppWarning);
             }
 
             if (permissionNames == null) {
-                ArraySet<String> cmp = ps.getDisabledComponents(user.id);
+                Set<String> cmp = userState.getDisabledComponents();
                 if (cmp != null && cmp.size() > 0) {
                     pw.print(prefix); pw.println("    disabledComponents:");
                     for (String s : cmp) {
                         pw.print(prefix); pw.print("      "); pw.println(s);
                     }
                 }
-                cmp = ps.getEnabledComponents(user.id);
+                cmp = userState.getEnabledComponents();
                 if (cmp != null && cmp.size() > 0) {
                     pw.print(prefix); pw.println("    enabledComponents:");
                     for (String s : cmp) {
@@ -5291,9 +5318,10 @@
 
     public void writePermissionStateForUserLPr(int userId, boolean sync) {
         if (sync) {
-            mRuntimePermissionsPersistence.writeStateForUserSyncLPr(userId);
+            mRuntimePermissionsPersistence.writeStateForUserSync(userId, mPermissionDataProvider,
+                    mPackages, mSharedUsers);
         } else {
-            mRuntimePermissionsPersistence.writeStateForUserAsyncLPr(userId);
+            mRuntimePermissionsPersistence.writeStateForUserAsync(userId);
         }
     }
 
@@ -5368,7 +5396,7 @@
         }
     }
 
-    private final class RuntimePermissionPersistence {
+    private static final class RuntimePermissionPersistence {
         private static final long WRITE_PERMISSIONS_DELAY_MILLIS = 200;
         private static final long MAX_WRITE_PERMISSIONS_DELAY_MILLIS = 2000;
 
@@ -5381,6 +5409,8 @@
 
         private final Handler mHandler = new MyHandler();
 
+        private final Object mLock = new Object();
+
         @GuardedBy("mLock")
         private final SparseBooleanArray mWriteScheduled = new SparseBooleanArray();
 
@@ -5400,45 +5430,58 @@
         // The mapping keys are user ids.
         private final SparseBooleanArray mPermissionUpgradeNeeded = new SparseBooleanArray();
 
-        public RuntimePermissionPersistence(RuntimePermissionsPersistence persistence) {
+        // This is a hack to allow this class to invoke a write using Settings's data structures,
+        // to facilitate moving to a finer scoped lock without a significant refactor.
+        private final Consumer<Integer> mInvokeWriteUserStateAsyncCallback;
+
+        public RuntimePermissionPersistence(RuntimePermissionsPersistence persistence,
+                Consumer<Integer> invokeWriteUserStateAsyncCallback) {
             mPersistence = persistence;
+            mInvokeWriteUserStateAsyncCallback = invokeWriteUserStateAsyncCallback;
         }
 
-        @GuardedBy("Settings.this.mLock")
-        int getVersionLPr(int userId) {
-            return mVersions.get(userId, INITIAL_VERSION);
-        }
-
-        @GuardedBy("Settings.this.mLock")
-        void setVersionLPr(int version, int userId) {
-            mVersions.put(userId, version);
-            writeStateForUserAsyncLPr(userId);
-        }
-
-        @GuardedBy("Settings.this.mLock")
-        public boolean isPermissionUpgradeNeeded(int userId) {
-            return mPermissionUpgradeNeeded.get(userId, true);
-        }
-
-        @GuardedBy("Settings.this.mLock")
-        public void updateRuntimePermissionsFingerprintLPr(@UserIdInt int userId) {
-            if (mExtendedFingerprint == null) {
-                throw new RuntimeException("The version of the permission controller hasn't been "
-                        + "set before trying to update the fingerprint.");
+        int getVersion(int userId) {
+            synchronized (mLock) {
+                return mVersions.get(userId, INITIAL_VERSION);
             }
-            mFingerprints.put(userId, mExtendedFingerprint);
-            writeStateForUserAsyncLPr(userId);
+        }
+
+        void setVersion(int version, int userId) {
+            synchronized (mLock) {
+                mVersions.put(userId, version);
+                writeStateForUserAsync(userId);
+            }
+        }
+
+        public boolean isPermissionUpgradeNeeded(int userId) {
+            synchronized (mLock) {
+                return mPermissionUpgradeNeeded.get(userId, true);
+            }
+        }
+
+        public void updateRuntimePermissionsFingerprint(@UserIdInt int userId) {
+            synchronized (mLock) {
+                if (mExtendedFingerprint == null) {
+                    throw new RuntimeException(
+                            "The version of the permission controller hasn't been "
+                                    + "set before trying to update the fingerprint.");
+                }
+                mFingerprints.put(userId, mExtendedFingerprint);
+                writeStateForUserAsync(userId);
+            }
         }
 
         public void setPermissionControllerVersion(long version) {
-            int numUser = mFingerprints.size();
-            mExtendedFingerprint = getExtendedFingerprint(version);
+            synchronized (mLock) {
+                int numUser = mFingerprints.size();
+                mExtendedFingerprint = getExtendedFingerprint(version);
 
-            for (int i = 0;  i < numUser; i++) {
-                int userId = mFingerprints.keyAt(i);
-                String fingerprint = mFingerprints.valueAt(i);
-                mPermissionUpgradeNeeded.put(userId,
-                        !TextUtils.equals(mExtendedFingerprint, fingerprint));
+                for (int i = 0; i < numUser; i++) {
+                    int userId = mFingerprints.keyAt(i);
+                    String fingerprint = mFingerprints.valueAt(i);
+                    mPermissionUpgradeNeeded.put(userId,
+                            !TextUtils.equals(mExtendedFingerprint, fingerprint));
+                }
             }
         }
 
@@ -5446,84 +5489,92 @@
             return PackagePartitions.FINGERPRINT + "?pc_version=" + version;
         }
 
-        public void writeStateForUserAsyncLPr(int userId) {
-            final long currentTimeMillis = SystemClock.uptimeMillis();
+        public void writeStateForUserAsync(int userId) {
+            synchronized (mLock) {
+                final long currentTimeMillis = SystemClock.uptimeMillis();
 
-            if (mWriteScheduled.get(userId)) {
-                mHandler.removeMessages(userId);
+                if (mWriteScheduled.get(userId)) {
+                    mHandler.removeMessages(userId);
 
-                // If enough time passed, write without holding off anymore.
-                final long lastNotWrittenMutationTimeMillis = mLastNotWrittenMutationTimesMillis
-                        .get(userId);
-                final long timeSinceLastNotWrittenMutationMillis = currentTimeMillis
-                        - lastNotWrittenMutationTimeMillis;
-                if (timeSinceLastNotWrittenMutationMillis >= MAX_WRITE_PERMISSIONS_DELAY_MILLIS) {
-                    mHandler.obtainMessage(userId).sendToTarget();
-                    return;
+                    // If enough time passed, write without holding off anymore.
+                    final long lastNotWrittenMutationTimeMillis = mLastNotWrittenMutationTimesMillis
+                            .get(userId);
+                    final long timeSinceLastNotWrittenMutationMillis = currentTimeMillis
+                            - lastNotWrittenMutationTimeMillis;
+                    if (timeSinceLastNotWrittenMutationMillis
+                            >= MAX_WRITE_PERMISSIONS_DELAY_MILLIS) {
+                        mHandler.obtainMessage(userId).sendToTarget();
+                        return;
+                    }
+
+                    // Hold off a bit more as settings are frequently changing.
+                    final long maxDelayMillis = Math.max(lastNotWrittenMutationTimeMillis
+                            + MAX_WRITE_PERMISSIONS_DELAY_MILLIS - currentTimeMillis, 0);
+                    final long writeDelayMillis = Math.min(WRITE_PERMISSIONS_DELAY_MILLIS,
+                            maxDelayMillis);
+
+                    Message message = mHandler.obtainMessage(userId);
+                    mHandler.sendMessageDelayed(message, writeDelayMillis);
+                } else {
+                    mLastNotWrittenMutationTimesMillis.put(userId, currentTimeMillis);
+                    Message message = mHandler.obtainMessage(userId);
+                    mHandler.sendMessageDelayed(message, WRITE_PERMISSIONS_DELAY_MILLIS);
+                    mWriteScheduled.put(userId, true);
                 }
-
-                // Hold off a bit more as settings are frequently changing.
-                final long maxDelayMillis = Math.max(lastNotWrittenMutationTimeMillis
-                        + MAX_WRITE_PERMISSIONS_DELAY_MILLIS - currentTimeMillis, 0);
-                final long writeDelayMillis = Math.min(WRITE_PERMISSIONS_DELAY_MILLIS,
-                        maxDelayMillis);
-
-                Message message = mHandler.obtainMessage(userId);
-                mHandler.sendMessageDelayed(message, writeDelayMillis);
-            } else {
-                mLastNotWrittenMutationTimesMillis.put(userId, currentTimeMillis);
-                Message message = mHandler.obtainMessage(userId);
-                mHandler.sendMessageDelayed(message, WRITE_PERMISSIONS_DELAY_MILLIS);
-                mWriteScheduled.put(userId, true);
             }
         }
 
-        public void writeStateForUserSyncLPr(int userId) {
-            mHandler.removeMessages(userId);
-            mWriteScheduled.delete(userId);
+        public void writeStateForUserSync(int userId, @NonNull LegacyPermissionDataProvider
+                legacyPermissionDataProvider,
+                @NonNull WatchedArrayMap<String, ? extends PackageStateInternal> packageStates,
+                @NonNull WatchedArrayMap<String, SharedUserSetting> sharedUsers) {
+            synchronized (mLock) {
+                mHandler.removeMessages(userId);
+                mWriteScheduled.delete(userId);
 
-            mPermissionDataProvider.writeLegacyPermissionStateTEMP();
+                legacyPermissionDataProvider.writeLegacyPermissionStateTEMP();
 
-            int version = mVersions.get(userId, INITIAL_VERSION);
+                int version = mVersions.get(userId, INITIAL_VERSION);
 
-            String fingerprint = mFingerprints.get(userId);
+                String fingerprint = mFingerprints.get(userId);
 
-            Map<String, List<RuntimePermissionsState.PermissionState>> packagePermissions =
-                    new ArrayMap<>();
-            int packagesSize = mPackages.size();
-            for (int i = 0; i < packagesSize; i++) {
-                String packageName = mPackages.keyAt(i);
-                PackageSetting packageSetting = mPackages.valueAt(i);
-                if (packageSetting.getSharedUser() == null) {
+                Map<String, List<RuntimePermissionsState.PermissionState>> packagePermissions =
+                        new ArrayMap<>();
+                int packagesSize = packageStates.size();
+                for (int i = 0; i < packagesSize; i++) {
+                    String packageName = packageStates.keyAt(i);
+                    PackageStateInternal packageState = packageStates.valueAt(i);
+                    if (packageState.getSharedUser() == null) {
+                        List<RuntimePermissionsState.PermissionState> permissions =
+                                getPermissionsFromPermissionsState(
+                                        packageState.getLegacyPermissionState(), userId);
+                        if (permissions.isEmpty() && !packageState.isInstallPermissionsFixed()) {
+                            // Storing an empty state means the package is known to the system and
+                            // its install permissions have been granted and fixed. If this is not
+                            // the case, we should not store anything.
+                            continue;
+                        }
+                        packagePermissions.put(packageName, permissions);
+                    }
+                }
+
+                Map<String, List<RuntimePermissionsState.PermissionState>> sharedUserPermissions =
+                        new ArrayMap<>();
+                final int sharedUsersSize = sharedUsers.size();
+                for (int i = 0; i < sharedUsersSize; i++) {
+                    String sharedUserName = sharedUsers.keyAt(i);
+                    SharedUserSetting sharedUserSetting = sharedUsers.valueAt(i);
                     List<RuntimePermissionsState.PermissionState> permissions =
                             getPermissionsFromPermissionsState(
-                                    packageSetting.getLegacyPermissionState(), userId);
-                    if (permissions.isEmpty() && !packageSetting.isInstallPermissionsFixed()) {
-                        // Storing an empty state means the package is known to the system and its
-                        // install permissions have been granted and fixed. If this is not the case,
-                        // we should not store anything.
-                        continue;
-                    }
-                    packagePermissions.put(packageName, permissions);
+                                    sharedUserSetting.getLegacyPermissionState(), userId);
+                    sharedUserPermissions.put(sharedUserName, permissions);
                 }
+
+                RuntimePermissionsState runtimePermissions = new RuntimePermissionsState(version,
+                        fingerprint, packagePermissions, sharedUserPermissions);
+
+                mPersistence.writeForUser(runtimePermissions, UserHandle.of(userId));
             }
-
-            Map<String, List<RuntimePermissionsState.PermissionState>> sharedUserPermissions =
-                    new ArrayMap<>();
-            final int sharedUsersSize = mSharedUsers.size();
-            for (int i = 0; i < sharedUsersSize; i++) {
-                String sharedUserName = mSharedUsers.keyAt(i);
-                SharedUserSetting sharedUserSetting = mSharedUsers.valueAt(i);
-                List<RuntimePermissionsState.PermissionState> permissions =
-                        getPermissionsFromPermissionsState(
-                                sharedUserSetting.getLegacyPermissionState(), userId);
-                sharedUserPermissions.put(sharedUserName, permissions);
-            }
-
-            RuntimePermissionsState runtimePermissions = new RuntimePermissionsState(version,
-                    fingerprint, packagePermissions, sharedUserPermissions);
-
-            mPersistence.writeForUser(runtimePermissions, UserHandle.of(userId));
         }
 
         @NonNull
@@ -5541,82 +5592,91 @@
             return permissions;
         }
 
-        @GuardedBy("Settings.this.mLock")
-        private void onUserRemovedLPw(int userId) {
-            // Make sure we do not
-            mHandler.removeMessages(userId);
+        private void onUserRemoved(int userId) {
+            synchronized (mLock) {
+                // Make sure we do not
+                mHandler.removeMessages(userId);
 
-            mPermissionUpgradeNeeded.delete(userId);
-            mVersions.delete(userId);
-            mFingerprints.remove(userId);
+                mPermissionUpgradeNeeded.delete(userId);
+                mVersions.delete(userId);
+                mFingerprints.remove(userId);
+            }
         }
 
         public void deleteUserRuntimePermissionsFile(int userId) {
-            mPersistence.deleteForUser(UserHandle.of(userId));
+            synchronized (mLock) {
+                mPersistence.deleteForUser(UserHandle.of(userId));
+            }
         }
 
-        @GuardedBy("Settings.this.mLock")
-        public void readStateForUserSyncLPr(int userId) {
-            RuntimePermissionsState runtimePermissions = mPersistence.readForUser(UserHandle.of(
-                    userId));
-            if (runtimePermissions == null) {
-                readLegacyStateForUserSyncLPr(userId);
-                writeStateForUserAsyncLPr(userId);
-                return;
-            }
-
-            // If the runtime permissions file exists but the version is not set this is
-            // an upgrade from P->Q. Hence mark it with the special UPGRADE_VERSION.
-            int version = runtimePermissions.getVersion();
-            if (version == RuntimePermissionsState.NO_VERSION) {
-                version = UPGRADE_VERSION;
-            }
-            mVersions.put(userId, version);
-
-            String fingerprint = runtimePermissions.getFingerprint();
-            mFingerprints.put(userId, fingerprint);
-
-            boolean isUpgradeToR = getInternalVersion().sdkVersion < Build.VERSION_CODES.R;
-
-            Map<String, List<RuntimePermissionsState.PermissionState>> packagePermissions =
-                    runtimePermissions.getPackagePermissions();
-            int packagesSize = mPackages.size();
-            for (int i = 0; i < packagesSize; i++) {
-                String packageName = mPackages.keyAt(i);
-                PackageSetting packageSetting = mPackages.valueAt(i);
-
-                List<RuntimePermissionsState.PermissionState> permissions =
-                        packagePermissions.get(packageName);
-                if (permissions != null) {
-                    readPermissionsStateLpr(permissions, packageSetting.getLegacyPermissionState(),
-                            userId);
-                    packageSetting.setInstallPermissionsFixed(true);
-                } else if (packageSetting.getSharedUser() == null && !isUpgradeToR) {
-                    Slog.w(TAG, "Missing permission state for package: " + packageName);
-                    packageSetting.getLegacyPermissionState().setMissing(true, userId);
+        public void readStateForUserSync(int userId, @NonNull VersionInfo internalVersion,
+                @NonNull WatchedArrayMap<String, PackageSetting> packageSettings,
+                @NonNull WatchedArrayMap<String, SharedUserSetting> sharedUsers,
+                @NonNull File userRuntimePermissionsFile) {
+            synchronized (mLock) {
+                RuntimePermissionsState runtimePermissions = mPersistence.readForUser(UserHandle.of(
+                        userId));
+                if (runtimePermissions == null) {
+                    readLegacyStateForUserSync(userId, userRuntimePermissionsFile, packageSettings,
+                            sharedUsers);
+                    writeStateForUserAsync(userId);
+                    return;
                 }
-            }
 
-            Map<String, List<RuntimePermissionsState.PermissionState>> sharedUserPermissions =
-                    runtimePermissions.getSharedUserPermissions();
-            int sharedUsersSize = mSharedUsers.size();
-            for (int i = 0; i < sharedUsersSize; i++) {
-                String sharedUserName = mSharedUsers.keyAt(i);
-                SharedUserSetting sharedUserSetting = mSharedUsers.valueAt(i);
+                // If the runtime permissions file exists but the version is not set this is
+                // an upgrade from P->Q. Hence mark it with the special UPGRADE_VERSION.
+                int version = runtimePermissions.getVersion();
+                if (version == RuntimePermissionsState.NO_VERSION) {
+                    version = UPGRADE_VERSION;
+                }
+                mVersions.put(userId, version);
 
-                List<RuntimePermissionsState.PermissionState> permissions =
-                        sharedUserPermissions.get(sharedUserName);
-                if (permissions != null) {
-                    readPermissionsStateLpr(permissions,
-                            sharedUserSetting.getLegacyPermissionState(), userId);
-                } else if (!isUpgradeToR) {
-                    Slog.w(TAG, "Missing permission state for shared user: " + sharedUserName);
-                    sharedUserSetting.getLegacyPermissionState().setMissing(true, userId);
+                String fingerprint = runtimePermissions.getFingerprint();
+                mFingerprints.put(userId, fingerprint);
+
+                boolean isUpgradeToR = internalVersion.sdkVersion < Build.VERSION_CODES.R;
+
+                Map<String, List<RuntimePermissionsState.PermissionState>> packagePermissions =
+                        runtimePermissions.getPackagePermissions();
+                int packagesSize = packageSettings.size();
+                for (int i = 0; i < packagesSize; i++) {
+                    String packageName = packageSettings.keyAt(i);
+                    PackageSetting packageSetting = packageSettings.valueAt(i);
+
+                    List<RuntimePermissionsState.PermissionState> permissions =
+                            packagePermissions.get(packageName);
+                    if (permissions != null) {
+                        readPermissionsState(permissions,
+                                packageSetting.getLegacyPermissionState(),
+                                userId);
+                        packageSetting.setInstallPermissionsFixed(true);
+                    } else if (packageSetting.getSharedUser() == null && !isUpgradeToR) {
+                        Slog.w(TAG, "Missing permission state for package: " + packageName);
+                        packageSetting.getLegacyPermissionState().setMissing(true, userId);
+                    }
+                }
+
+                Map<String, List<RuntimePermissionsState.PermissionState>> sharedUserPermissions =
+                        runtimePermissions.getSharedUserPermissions();
+                int sharedUsersSize = sharedUsers.size();
+                for (int i = 0; i < sharedUsersSize; i++) {
+                    String sharedUserName = sharedUsers.keyAt(i);
+                    SharedUserSetting sharedUserSetting = sharedUsers.valueAt(i);
+
+                    List<RuntimePermissionsState.PermissionState> permissions =
+                            sharedUserPermissions.get(sharedUserName);
+                    if (permissions != null) {
+                        readPermissionsState(permissions,
+                                sharedUserSetting.getLegacyPermissionState(), userId);
+                    } else if (!isUpgradeToR) {
+                        Slog.w(TAG, "Missing permission state for shared user: " + sharedUserName);
+                        sharedUserSetting.getLegacyPermissionState().setMissing(true, userId);
+                    }
                 }
             }
         }
 
-        private void readPermissionsStateLpr(
+        private void readPermissionsState(
                 @NonNull List<RuntimePermissionsState.PermissionState> permissions,
                 @NonNull LegacyPermissionState permissionsState, @UserIdInt int userId) {
             int permissionsSize = permissions.size();
@@ -5630,77 +5690,86 @@
             }
         }
 
-        @GuardedBy("Settings.this.mLock")
-        private void readLegacyStateForUserSyncLPr(int userId) {
-            File permissionsFile = getUserRuntimePermissionsFile(userId);
-            if (!permissionsFile.exists()) {
-                return;
-            }
+        private void readLegacyStateForUserSync(int userId, @NonNull File permissionsFile,
+                @NonNull WatchedArrayMap<String, ? extends PackageStateInternal> packageStates,
+                @NonNull WatchedArrayMap<String, SharedUserSetting> sharedUsers) {
+            synchronized (mLock) {
+                if (!permissionsFile.exists()) {
+                    return;
+                }
 
-            FileInputStream in;
-            try {
-                in = new AtomicFile(permissionsFile).openRead();
-            } catch (FileNotFoundException fnfe) {
-                Slog.i(PackageManagerService.TAG, "No permissions state");
-                return;
-            }
+                FileInputStream in;
+                try {
+                    in = new AtomicFile(permissionsFile).openRead();
+                } catch (FileNotFoundException fnfe) {
+                    Slog.i(PackageManagerService.TAG, "No permissions state");
+                    return;
+                }
 
-            try {
-                final TypedXmlPullParser parser = Xml.resolvePullParser(in);
-                parseLegacyRuntimePermissionsLPr(parser, userId);
+                try {
+                    final TypedXmlPullParser parser = Xml.resolvePullParser(in);
+                    parseLegacyRuntimePermissions(parser, userId, packageStates, sharedUsers);
 
-            } catch (XmlPullParserException | IOException e) {
-                throw new IllegalStateException("Failed parsing permissions file: "
-                        + permissionsFile, e);
-            } finally {
-                IoUtils.closeQuietly(in);
+                } catch (XmlPullParserException | IOException e) {
+                    throw new IllegalStateException("Failed parsing permissions file: "
+                            + permissionsFile, e);
+                } finally {
+                    IoUtils.closeQuietly(in);
+                }
             }
         }
 
-        // Private internals
-
-        @GuardedBy("Settings.this.mLock")
-        private void parseLegacyRuntimePermissionsLPr(TypedXmlPullParser parser, int userId)
+        private void parseLegacyRuntimePermissions(TypedXmlPullParser parser, int userId,
+                @NonNull WatchedArrayMap<String, ? extends PackageStateInternal> packageStates,
+                @NonNull WatchedArrayMap<String, SharedUserSetting> sharedUsers)
                 throws IOException, XmlPullParserException {
-            final int outerDepth = parser.getDepth();
-            int type;
-            while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                    && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
-                if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
-                    continue;
-                }
+            synchronized (mLock) {
+                final int outerDepth = parser.getDepth();
+                int type;
+                while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                        && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+                    if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                        continue;
+                    }
 
-                switch (parser.getName()) {
-                    case TAG_RUNTIME_PERMISSIONS: {
-                        // If the permisions settings file exists but the version is not set this is
-                        // an upgrade from P->Q. Hence mark it with the special UPGRADE_VERSION
-                        int version = parser.getAttributeInt(null, ATTR_VERSION, UPGRADE_VERSION);
-                        mVersions.put(userId, version);
-                        String fingerprint = parser.getAttributeValue(null, ATTR_FINGERPRINT);
-                        mFingerprints.put(userId, fingerprint);
-                    } break;
-
-                    case TAG_PACKAGE: {
-                        String name = parser.getAttributeValue(null, ATTR_NAME);
-                        PackageSetting ps = mPackages.get(name);
-                        if (ps == null) {
-                            Slog.w(PackageManagerService.TAG, "Unknown package:" + name);
-                            XmlUtils.skipCurrentTag(parser);
-                            continue;
+                    switch (parser.getName()) {
+                        case TAG_RUNTIME_PERMISSIONS: {
+                            // If the permisions settings file exists but the version is not set this is
+                            // an upgrade from P->Q. Hence mark it with the special UPGRADE_VERSION
+                            int version = parser.getAttributeInt(null, ATTR_VERSION,
+                                    UPGRADE_VERSION);
+                            mVersions.put(userId, version);
+                            String fingerprint = parser.getAttributeValue(null, ATTR_FINGERPRINT);
+                            mFingerprints.put(userId, fingerprint);
                         }
-                        parseLegacyPermissionsLPr(parser, ps.getLegacyPermissionState(), userId);
-                    } break;
+                        break;
 
-                    case TAG_SHARED_USER: {
-                        String name = parser.getAttributeValue(null, ATTR_NAME);
-                        SharedUserSetting sus = mSharedUsers.get(name);
-                        if (sus == null) {
-                            Slog.w(PackageManagerService.TAG, "Unknown shared user:" + name);
-                            XmlUtils.skipCurrentTag(parser);
-                            continue;
+                        case TAG_PACKAGE: {
+                            String name = parser.getAttributeValue(null, ATTR_NAME);
+                            PackageStateInternal ps = packageStates.get(name);
+                            if (ps == null) {
+                                Slog.w(PackageManagerService.TAG, "Unknown package:" + name);
+                                XmlUtils.skipCurrentTag(parser);
+                                continue;
+                            }
+                            parseLegacyPermissionsLPr(parser, ps.getLegacyPermissionState(),
+                                    userId);
                         }
-                        parseLegacyPermissionsLPr(parser, sus.getLegacyPermissionState(), userId);
-                    } break;
+                        break;
+
+                        case TAG_SHARED_USER: {
+                            String name = parser.getAttributeValue(null, ATTR_NAME);
+                            SharedUserSetting sus = sharedUsers.get(name);
+                            if (sus == null) {
+                                Slog.w(PackageManagerService.TAG, "Unknown shared user:" + name);
+                                XmlUtils.skipCurrentTag(parser);
+                                continue;
+                            }
+                            parseLegacyPermissionsLPr(parser, sus.getLegacyPermissionState(),
+                                    userId);
+                        }
+                        break;
+                    }
                 }
             }
         }
@@ -5708,25 +5777,27 @@
         private void parseLegacyPermissionsLPr(TypedXmlPullParser parser,
                 LegacyPermissionState permissionsState, int userId)
                 throws IOException, XmlPullParserException {
-            final int outerDepth = parser.getDepth();
-            int type;
-            while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                    && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
-                if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
-                    continue;
-                }
-
-                switch (parser.getName()) {
-                    case TAG_ITEM: {
-                        String name = parser.getAttributeValue(null, ATTR_NAME);
-                        final boolean granted =
-                                parser.getAttributeBoolean(null, ATTR_GRANTED, true);
-                        final int flags =
-                                parser.getAttributeIntHex(null, ATTR_FLAGS, 0);
-                        permissionsState.putPermissionState(new PermissionState(name, true,
-                                granted, flags), userId);
+            synchronized (mLock) {
+                final int outerDepth = parser.getDepth();
+                int type;
+                while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                        && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+                    if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                        continue;
                     }
-                    break;
+
+                    switch (parser.getName()) {
+                        case TAG_ITEM: {
+                            String name = parser.getAttributeValue(null, ATTR_NAME);
+                            final boolean granted =
+                                    parser.getAttributeBoolean(null, ATTR_GRANTED, true);
+                            final int flags =
+                                    parser.getAttributeIntHex(null, ATTR_FLAGS, 0);
+                            permissionsState.putPermissionState(new PermissionState(name, true,
+                                    granted, flags), userId);
+                        }
+                        break;
+                    }
                 }
             }
         }
@@ -5740,9 +5811,7 @@
             public void handleMessage(Message message) {
                 final int userId = message.what;
                 Runnable callback = (Runnable) message.obj;
-                synchronized (mLock) {
-                    writeStateForUserSyncLPr(userId);
-                }
+                mInvokeWriteUserStateAsyncCallback.accept(userId);
                 if (callback != null) {
                     callback.run();
                 }
diff --git a/services/core/java/com/android/server/pm/SharedLibrariesImpl.java b/services/core/java/com/android/server/pm/SharedLibrariesImpl.java
new file mode 100644
index 0000000..0055f4e
--- /dev/null
+++ b/services/core/java/com/android/server/pm/SharedLibrariesImpl.java
@@ -0,0 +1,824 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.PLATFORM_PACKAGE_NAME;
+import static com.android.server.pm.PackageManagerService.TAG;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.pm.PackageManager;
+import android.content.pm.SharedLibraryInfo;
+import android.content.pm.VersionedPackage;
+import android.os.Process;
+import android.os.UserHandle;
+import android.os.storage.StorageManager;
+import android.service.pm.PackageServiceDumpProto;
+import android.util.ArraySet;
+import android.util.Pair;
+import android.util.Slog;
+import android.util.proto.ProtoOutputStream;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.ArrayUtils;
+import com.android.server.SystemConfig;
+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.Watchable;
+import com.android.server.utils.WatchableImpl;
+import com.android.server.utils.Watched;
+import com.android.server.utils.WatchedArrayMap;
+import com.android.server.utils.WatchedLongSparseArray;
+import com.android.server.utils.Watcher;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.BiConsumer;
+
+/**
+ * Current known shared libraries on the device.
+ */
+public final class SharedLibrariesImpl implements SharedLibrariesRead, Watchable, Snappable {
+
+    // TODO(b/200588896): remove PMS dependency
+    private final PackageManagerService mPm;
+    private final PackageManagerServiceInjector mInjector;
+    private DeletePackageHelper mDeletePackageHelper; // late init
+
+    // A map of library name to a list of {@link SharedLibraryInfo}s with different versions.
+    @Watched
+    private final WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>>
+            mSharedLibraries;
+    private final SnapshotCache<WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>>>
+            mSharedLibrariesSnapshot;
+
+    // A map of declaring package name to a list of {@link SharedLibraryInfo}s with different
+    // versions.
+    @Watched
+    private final WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>>
+            mStaticLibsByDeclaringPackage;
+    private final SnapshotCache<WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>>>
+            mStaticLibsByDeclaringPackageSnapshot;
+
+    /**
+     * Watchable machinery
+     */
+    private final WatchableImpl mWatchable = new WatchableImpl();
+
+    /**
+     * The observer that watches for changes from array members
+     */
+    private final Watcher mObserver = new Watcher() {
+        @Override
+        public void onChange(@Nullable Watchable what) {
+            SharedLibrariesImpl.this.dispatchChange(what);
+        }
+    };
+
+    private final SnapshotCache<SharedLibrariesImpl> mSnapshot;
+
+    // Create a snapshot cache
+    private SnapshotCache<SharedLibrariesImpl> makeCache() {
+        return new SnapshotCache<SharedLibrariesImpl>(this /* source */, this /* watchable */) {
+            @Override
+            public SharedLibrariesImpl createSnapshot() {
+                final SharedLibrariesImpl sharedLibrariesImpl = new SharedLibrariesImpl(mSource);
+                sharedLibrariesImpl.mWatchable.seal();
+                return sharedLibrariesImpl;
+            }};
+    }
+
+    /**
+     * Default constructor used in PackageManagerService.
+     */
+    SharedLibrariesImpl(PackageManagerService pm, PackageManagerServiceInjector injector) {
+        mPm = pm;
+        mInjector = injector;
+
+        mSharedLibraries = new WatchedArrayMap<>();
+        mSharedLibrariesSnapshot = new SnapshotCache.Auto<>(mSharedLibraries, mSharedLibraries,
+                "SharedLibrariesImpl.mSharedLibraries");
+        mStaticLibsByDeclaringPackage = new WatchedArrayMap<>();
+        mStaticLibsByDeclaringPackageSnapshot = new SnapshotCache.Auto<>(
+                mStaticLibsByDeclaringPackage, mStaticLibsByDeclaringPackage,
+                "SharedLibrariesImpl.mStaticLibsByDeclaringPackage");
+
+        registerObservers();
+        Watchable.verifyWatchedAttributes(this, mObserver);
+        mSnapshot = makeCache();
+    }
+
+    /**
+     * Invoked by PMS constructor after the instance of {@link DeletePackageHelper} is ready.
+     */
+    void setDeletePackageHelper(DeletePackageHelper deletePackageHelper) {
+        mDeletePackageHelper = deletePackageHelper;
+    }
+
+    private void registerObservers() {
+        mSharedLibraries.registerObserver(mObserver);
+        mStaticLibsByDeclaringPackage.registerObserver(mObserver);
+    }
+
+    /**
+     * A copy constructor used in snapshot().
+     */
+    private SharedLibrariesImpl(SharedLibrariesImpl source) {
+        mPm = source.mPm;
+        mInjector = source.mInjector;
+
+        mSharedLibraries = source.mSharedLibrariesSnapshot.snapshot();
+        mSharedLibrariesSnapshot = new SnapshotCache.Sealed<>();
+        mStaticLibsByDeclaringPackage = source.mStaticLibsByDeclaringPackageSnapshot.snapshot();
+        mStaticLibsByDeclaringPackageSnapshot = new SnapshotCache.Sealed<>();
+
+        // Do not register any Watchables and do not create a snapshot cache.
+        mSnapshot = new SnapshotCache.Sealed();
+    }
+
+    /**
+     * Ensures an observer is in the list, exactly once. The observer cannot be null.  The
+     * function quietly returns if the observer is already in the list.
+     *
+     * @param observer The {@link Watcher} to be notified when the {@link Watchable} changes.
+     */
+    @Override
+    public void registerObserver(@NonNull Watcher observer) {
+        mWatchable.registerObserver(observer);
+    }
+
+    /**
+     * Ensures an observer is not in the list. The observer must not be null.  The function
+     * quietly returns if the objserver is not in the list.
+     *
+     * @param observer The {@link Watcher} that should not be in the notification list.
+     */
+    @Override
+    public void unregisterObserver(@NonNull Watcher observer) {
+        mWatchable.unregisterObserver(observer);
+    }
+
+    /**
+     * Return true if the {@link Watcher} is a registered observer.
+     * @param observer A {@link Watcher} that might be registered
+     * @return true if the observer is registered with this {@link Watchable}.
+     */
+    @Override
+    public boolean isRegisteredObserver(@NonNull Watcher observer) {
+        return mWatchable.isRegisteredObserver(observer);
+    }
+
+    /**
+     * Invokes {@link Watcher#onChange} on each registered observer.  The method can be called
+     * with the {@link Watchable} that generated the event.  In a tree of {@link Watchable}s, this
+     * is generally the first (deepest) {@link Watchable} to detect a change.
+     *
+     * @param what The {@link Watchable} that generated the event.
+     */
+    @Override
+    public void dispatchChange(@Nullable Watchable what) {
+        mWatchable.dispatchChange(what);
+    }
+
+    /**
+     * Create an immutable copy of the object, suitable for read-only methods.  A snapshot
+     * is free to omit state that is only needed for mutating methods.
+     */
+    @Override
+    public @NonNull SharedLibrariesRead snapshot() {
+        return mSnapshot.snapshot();
+    }
+
+    /**
+     * Returns all shared libraries on the device.
+     */
+    @GuardedBy("mPm.mLock")
+    @Override
+    public @NonNull WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>> getAll() {
+        return mSharedLibraries;
+    }
+
+    /**
+     * Given the library name, returns a list of shared libraries on all versions.
+     */
+    @GuardedBy("mPm.mLock")
+    @Override
+    public @NonNull WatchedLongSparseArray<SharedLibraryInfo> getSharedLibraryInfos(
+            @NonNull String libName) {
+        return mSharedLibraries.get(libName);
+    }
+
+    /**
+     * Returns the shared library with given library name and version number.
+     */
+    @GuardedBy("mPm.mLock")
+    @Override
+    public @Nullable SharedLibraryInfo getSharedLibraryInfo(@NonNull String libName, long version) {
+        final WatchedLongSparseArray<SharedLibraryInfo> versionedLib =
+                mSharedLibraries.get(libName);
+        if (versionedLib == null) {
+            return null;
+        }
+        return versionedLib.get(version);
+    }
+
+    /**
+     * Given the declaring package name, returns a list of static shared libraries on all versions.
+     */
+    @GuardedBy("mPm.mLock")
+    @Override
+    public @NonNull WatchedLongSparseArray<SharedLibraryInfo> getStaticLibraryInfos(
+            @NonNull String declaringPackageName) {
+        return mStaticLibsByDeclaringPackage.get(declaringPackageName);
+    }
+
+    @GuardedBy("mPm.mLock")
+    private @Nullable PackageSetting getLibraryPackageLPr(@NonNull SharedLibraryInfo libInfo) {
+        final VersionedPackage declaringPackage = libInfo.getDeclaringPackage();
+        if (libInfo.isStatic()) {
+            // Resolve the package name - we use synthetic package names internally
+            final String internalPackageName = mPm.resolveInternalPackageNameLPr(
+                    declaringPackage.getPackageName(),
+                    declaringPackage.getLongVersionCode());
+            return mPm.mSettings.getPackageLPr(internalPackageName);
+        }
+        if (libInfo.isSdk()) {
+            return mPm.mSettings.getPackageLPr(declaringPackage.getPackageName());
+        }
+        return null;
+    }
+
+    /**
+     * Finds all unused shared libraries which have cached more than the given
+     * {@code maxCachePeriod}. Deletes them one by one until the available storage space on the
+     * device is larger than {@code neededSpace}.
+     *
+     * @param neededSpace A minimum available storage space the device needs to reach
+     * @param maxCachePeriod A maximum period of time an unused shared library can be cached
+     *                       on the device.
+     * @return {@code true} if the available storage space is reached.
+     */
+    boolean pruneUnusedStaticSharedLibraries(long neededSpace, long maxCachePeriod)
+            throws IOException {
+        final StorageManager storage = mInjector.getSystemService(StorageManager.class);
+        final File volume = storage.findPathForUuid(StorageManager.UUID_PRIVATE_INTERNAL);
+
+        List<VersionedPackage> packagesToDelete = null;
+        final long now = System.currentTimeMillis();
+
+        // Important: We skip shared libs used for some user since
+        // in such a case we need to keep the APK on the device. The check for
+        // a lib being used for any user is performed by the uninstall call.
+        synchronized (mPm.mLock) {
+            final int libCount = mSharedLibraries.size();
+            for (int i = 0; i < libCount; i++) {
+                final WatchedLongSparseArray<SharedLibraryInfo> versionedLib =
+                        mSharedLibraries.valueAt(i);
+                if (versionedLib == null) {
+                    continue;
+                }
+                final int versionCount = versionedLib.size();
+                for (int j = 0; j < versionCount; j++) {
+                    SharedLibraryInfo libInfo = versionedLib.valueAt(j);
+                    final PackageSetting ps = getLibraryPackageLPr(libInfo);
+                    if (ps == null) {
+                        continue;
+                    }
+                    // Skip unused libs cached less than the min period to prevent pruning a lib
+                    // needed by a subsequently installed package.
+                    if (now - ps.getLastUpdateTime() < maxCachePeriod) {
+                        continue;
+                    }
+
+                    if (ps.getPkg().isSystem()) {
+                        continue;
+                    }
+
+                    if (packagesToDelete == null) {
+                        packagesToDelete = new ArrayList<>();
+                    }
+                    packagesToDelete.add(new VersionedPackage(ps.getPkg().getPackageName(),
+                            libInfo.getDeclaringPackage().getLongVersionCode()));
+                }
+            }
+        }
+
+        if (packagesToDelete != null) {
+            final int packageCount = packagesToDelete.size();
+            for (int i = 0; i < packageCount; i++) {
+                final VersionedPackage pkgToDelete = packagesToDelete.get(i);
+                // Delete the package synchronously (will fail of the lib used for any user).
+                if (mDeletePackageHelper.deletePackageX(pkgToDelete.getPackageName(),
+                        pkgToDelete.getLongVersionCode(), UserHandle.USER_SYSTEM,
+                        PackageManager.DELETE_ALL_USERS,
+                        true /*removedBySystem*/) == PackageManager.DELETE_SUCCEEDED) {
+                    if (volume.getUsableSpace() >= neededSpace) {
+                        return true;
+                    }
+                }
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Given a package of static shared library, returns its shared library info of
+     * the latest version.
+     *
+     * @param pkg A package of static shared library.
+     * @return The latest version of shared library info.
+     */
+    @GuardedBy("mPm.mLock")
+    @Nullable SharedLibraryInfo getLatestSharedLibraVersionLPr(@NonNull AndroidPackage pkg) {
+        WatchedLongSparseArray<SharedLibraryInfo> versionedLib = mSharedLibraries.get(
+                pkg.getStaticSharedLibName());
+        if (versionedLib == null) {
+            return null;
+        }
+        long previousLibVersion = -1;
+        final int versionCount = versionedLib.size();
+        for (int i = 0; i < versionCount; i++) {
+            final long libVersion = versionedLib.keyAt(i);
+            if (libVersion < pkg.getStaticSharedLibVersion()) {
+                previousLibVersion = Math.max(previousLibVersion, libVersion);
+            }
+        }
+        if (previousLibVersion >= 0) {
+            return versionedLib.get(previousLibVersion);
+        }
+        return null;
+    }
+
+    /**
+     * Given a package scanned result of a static shared library, returns its package setting of
+     * the latest version
+     *
+     * @param scanResult The scanned result of a static shared library package.
+     * @return The package setting that represents the latest version of shared library info.
+     */
+    @Nullable
+    PackageSetting getStaticSharedLibLatestVersionSetting(@NonNull ScanResult scanResult) {
+        PackageSetting sharedLibPackage = null;
+        synchronized (mPm.mLock) {
+            final SharedLibraryInfo latestSharedLibraVersionLPr =
+                    getLatestSharedLibraVersionLPr(scanResult.mRequest.mParsedPackage);
+            if (latestSharedLibraVersionLPr != null) {
+                sharedLibPackage = mPm.mSettings.getPackageLPr(
+                        latestSharedLibraVersionLPr.getPackageName());
+            }
+        }
+        return sharedLibPackage;
+    }
+
+    /**
+     * Apply a given {@code action} to all the libraries defining in the package.
+     *
+     * @param pkg A package defining libraries.
+     * @param libInfo An extra shared library info passing to the action.
+     * @param action The action to apply.
+     */
+    @GuardedBy("mPm.mLock")
+    private void applyDefiningSharedLibraryUpdateLPr(
+            @NonNull AndroidPackage pkg, @Nullable SharedLibraryInfo libInfo,
+            @NonNull BiConsumer<SharedLibraryInfo, SharedLibraryInfo> action) {
+        // Note that libraries defined by this package may be null if:
+        // - Package manager was unable to create the shared library. The package still
+        //   gets installed, but the shared library does not get created.
+        // Or:
+        // - Package manager is in a state where package isn't scanned yet. This will
+        //   get called again after scanning to fix the dependencies.
+        if (AndroidPackageUtils.isLibrary(pkg)) {
+            if (pkg.getSdkLibName() != null) {
+                SharedLibraryInfo definedLibrary = getSharedLibraryInfo(
+                        pkg.getSdkLibName(), pkg.getSdkLibVersionMajor());
+                if (definedLibrary != null) {
+                    action.accept(definedLibrary, libInfo);
+                }
+            } else if (pkg.getStaticSharedLibName() != null) {
+                SharedLibraryInfo definedLibrary = getSharedLibraryInfo(
+                        pkg.getStaticSharedLibName(), pkg.getStaticSharedLibVersion());
+                if (definedLibrary != null) {
+                    action.accept(definedLibrary, libInfo);
+                }
+            } else {
+                for (String libraryName : pkg.getLibraryNames()) {
+                    SharedLibraryInfo definedLibrary = getSharedLibraryInfo(
+                            libraryName, SharedLibraryInfo.VERSION_UNDEFINED);
+                    if (definedLibrary != null) {
+                        action.accept(definedLibrary, libInfo);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Adds shared library {@code libInfo}'s self code paths and using library files to the list
+     * {@code usesLibraryFiles}. Also, adds the dependencies to the shared libraries that are
+     * defining in the {@code pkg}.
+     *
+     * @param pkg A package that is using the {@code libInfo}.
+     * @param usesLibraryFiles A list to add code paths to.
+     * @param libInfo A shared library info that is used by the {@code pkg}.
+     * @param changingLib The updating library package.
+     * @param changingLibSetting The updating library package setting.
+     */
+    @GuardedBy("mPm.mLock")
+    private void addSharedLibraryLPr(@NonNull AndroidPackage pkg,
+            @NonNull Set<String> usesLibraryFiles, @NonNull SharedLibraryInfo libInfo,
+            @Nullable AndroidPackage changingLib, @Nullable PackageSetting changingLibSetting) {
+        if (libInfo.getPath() != null) {
+            usesLibraryFiles.add(libInfo.getPath());
+            return;
+        }
+        AndroidPackage pkgForCodePaths = mPm.mPackages.get(libInfo.getPackageName());
+        PackageSetting pkgSetting = mPm.mSettings.getPackageLPr(libInfo.getPackageName());
+        if (changingLib != null && changingLib.getPackageName().equals(libInfo.getPackageName())) {
+            // If we are doing this while in the middle of updating a library apk,
+            // then we need to make sure to use that new apk for determining the
+            // dependencies here.  (We haven't yet finished committing the new apk
+            // to the package manager state.)
+            if (pkgForCodePaths == null
+                    || pkgForCodePaths.getPackageName().equals(changingLib.getPackageName())) {
+                pkgForCodePaths = changingLib;
+                pkgSetting = changingLibSetting;
+            }
+        }
+        if (pkgForCodePaths != null) {
+            usesLibraryFiles.addAll(AndroidPackageUtils.getAllCodePaths(pkgForCodePaths));
+            // If the package provides libraries, add the dependency to them.
+            applyDefiningSharedLibraryUpdateLPr(pkg, libInfo, SharedLibraryInfo::addDependency);
+            if (pkgSetting != null) {
+                usesLibraryFiles.addAll(pkgSetting.getPkgState().getUsesLibraryFiles());
+            }
+        }
+    }
+
+    /**
+     * Collects all shared libraries being used by the target package. Rebuilds the dependencies
+     * of shared libraries and update the correct shared library code paths for it.
+     *
+     * @param pkg The target package to update shared library dependency.
+     * @param pkgSetting The target's package setting.
+     * @param changingLib The updating library package.
+     * @param changingLibSetting The updating library package setting.
+     * @param availablePackages All installed packages and current being installed packages.
+     */
+    @GuardedBy("mPm.mLock")
+    void updateSharedLibrariesLPw(@NonNull AndroidPackage pkg, @NonNull PackageSetting pkgSetting,
+            @Nullable AndroidPackage changingLib, @Nullable PackageSetting changingLibSetting,
+            @NonNull Map<String, AndroidPackage> availablePackages)
+            throws PackageManagerException {
+        final ArrayList<SharedLibraryInfo> sharedLibraryInfos =
+                SharedLibraryHelper.collectSharedLibraryInfos(
+                        pkgSetting.getPkg(), availablePackages, mSharedLibraries,
+                        null /* newLibraries */, mInjector.getCompatibility());
+        executeSharedLibrariesUpdateLPw(pkg, pkgSetting, changingLib, changingLibSetting,
+                sharedLibraryInfos, mPm.mUserManager.getUserIds());
+    }
+
+    /**
+     * Rebuilds the dependencies of shared libraries for the target package, and update the
+     * shared library code paths to its package setting.
+     *
+     * @param pkg The target package to update shared library dependency.
+     * @param pkgSetting The target's package setting.
+     * @param changingLib The updating library package.
+     * @param changingLibSetting The updating library package setting.
+     * @param usesLibraryInfos The shared libraries used by the target package.
+     * @param allUsers All user ids on the device.
+     */
+    @GuardedBy("mPm.mLock")
+    void executeSharedLibrariesUpdateLPw(AndroidPackage pkg,
+            @NonNull PackageSetting pkgSetting, @Nullable AndroidPackage changingLib,
+            @Nullable PackageSetting changingLibSetting,
+            ArrayList<SharedLibraryInfo> usesLibraryInfos, int[] allUsers) {
+        // If the package provides libraries, clear their old dependencies.
+        // This method will set them up again.
+        applyDefiningSharedLibraryUpdateLPr(pkg, null, (definingLibrary, dependency) -> {
+            definingLibrary.clearDependencies();
+        });
+        if (usesLibraryInfos != null) {
+            pkgSetting.getPkgState().setUsesLibraryInfos(usesLibraryInfos);
+            // Use LinkedHashSet to preserve the order of files added to
+            // usesLibraryFiles while eliminating duplicates.
+            Set<String> usesLibraryFiles = new LinkedHashSet<>();
+            for (SharedLibraryInfo libInfo : usesLibraryInfos) {
+                addSharedLibraryLPr(pkg, usesLibraryFiles, libInfo, changingLib,
+                        changingLibSetting);
+            }
+            pkgSetting.setPkgStateLibraryFiles(usesLibraryFiles);
+
+            // let's make sure we mark all static shared libraries as installed for the same users
+            // that its dependent packages are installed for.
+            int[] installedUsers = new int[allUsers.length];
+            int installedUserCount = 0;
+            for (int u = 0; u < allUsers.length; u++) {
+                if (pkgSetting.getInstalled(allUsers[u])) {
+                    installedUsers[installedUserCount++] = allUsers[u];
+                }
+            }
+            for (SharedLibraryInfo sharedLibraryInfo : usesLibraryInfos) {
+                if (!sharedLibraryInfo.isStatic()) {
+                    continue;
+                }
+                final PackageSetting staticLibPkgSetting =
+                        mPm.getPackageSettingForMutation(sharedLibraryInfo.getPackageName());
+                if (staticLibPkgSetting == null) {
+                    Slog.wtf(TAG, "Shared lib without setting: " + sharedLibraryInfo);
+                    continue;
+                }
+                for (int u = 0; u < installedUserCount; u++) {
+                    staticLibPkgSetting.setInstalled(true, installedUsers[u]);
+                }
+            }
+        } else {
+            pkgSetting.getPkgState().setUsesLibraryInfos(Collections.emptyList())
+                    .setUsesLibraryFiles(Collections.emptyList());
+        }
+    }
+
+    private static boolean hasString(List<String> list, List<String> which) {
+        if (list == null || which == null) {
+            return false;
+        }
+        for (int i = list.size() - 1; i >= 0; i--) {
+            for (int j = which.size() - 1; j >= 0; j--) {
+                if (which.get(j).equals(list.get(i))) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Update shared library dependencies and code paths for applications that are using the
+     * library {@code updatedPkg}. Update all applications if the {@code updatedPkg} is null.
+     *
+     * @param updatedPkg The updating shared library package.
+     * @param updatedPkgSetting The updating shared library package setting.
+     * @param availablePackages All available packages on the device.
+     * @return Packages that has been updated.
+     */
+    @GuardedBy("mPm.mLock")
+    @Nullable ArrayList<AndroidPackage> updateAllSharedLibrariesLPw(
+            @Nullable AndroidPackage updatedPkg, @Nullable PackageSetting updatedPkgSetting,
+            @NonNull Map<String, AndroidPackage> availablePackages) {
+        ArrayList<AndroidPackage> resultList = null;
+        // Set of all descendants of a library; used to eliminate cycles
+        ArraySet<String> descendants = null;
+        // The current list of packages that need updating
+        List<Pair<AndroidPackage, PackageSetting>> needsUpdating = null;
+        if (updatedPkg != null && updatedPkgSetting != null) {
+            needsUpdating = new ArrayList<>(1);
+            needsUpdating.add(Pair.create(updatedPkg, updatedPkgSetting));
+        }
+        do {
+            final Pair<AndroidPackage, PackageSetting> changingPkgPair =
+                    (needsUpdating == null) ? null : needsUpdating.remove(0);
+            final AndroidPackage changingPkg = changingPkgPair != null
+                    ? changingPkgPair.first : null;
+            final PackageSetting changingPkgSetting = changingPkgPair != null
+                    ? changingPkgPair.second : null;
+            for (int i = mPm.mPackages.size() - 1; i >= 0; --i) {
+                final AndroidPackage pkg = mPm.mPackages.valueAt(i);
+                final PackageSetting pkgSetting = mPm.mSettings.getPackageLPr(pkg.getPackageName());
+                if (changingPkg != null
+                        && !hasString(pkg.getUsesLibraries(), changingPkg.getLibraryNames())
+                        && !hasString(pkg.getUsesOptionalLibraries(), changingPkg.getLibraryNames())
+                        && !ArrayUtils.contains(pkg.getUsesStaticLibraries(),
+                        changingPkg.getStaticSharedLibName())
+                        && !ArrayUtils.contains(pkg.getUsesSdkLibraries(),
+                        changingPkg.getSdkLibName())) {
+                    continue;
+                }
+                if (resultList == null) {
+                    resultList = new ArrayList<>();
+                }
+                resultList.add(pkg);
+                // if we're updating a shared library, all of its descendants must be updated
+                if (changingPkg != null) {
+                    if (descendants == null) {
+                        descendants = new ArraySet<>();
+                    }
+                    if (!descendants.contains(pkg.getPackageName())) {
+                        descendants.add(pkg.getPackageName());
+                        needsUpdating.add(Pair.create(pkg, pkgSetting));
+                    }
+                }
+                try {
+                    updateSharedLibrariesLPw(pkg, pkgSetting, changingPkg,
+                            changingPkgSetting, availablePackages);
+                } catch (PackageManagerException e) {
+                    // If a system app update or an app and a required lib missing we
+                    // delete the package and for updated system apps keep the data as
+                    // it is better for the user to reinstall than to be in an limbo
+                    // state. Also libs disappearing under an app should never happen
+                    // - just in case.
+                    if (!pkg.isSystem() || pkgSetting.getPkgState().isUpdatedSystemApp()) {
+                        final int flags = pkgSetting.getPkgState().isUpdatedSystemApp()
+                                ? PackageManager.DELETE_KEEP_DATA : 0;
+                        mDeletePackageHelper.deletePackageLIF(pkg.getPackageName(), null, true,
+                                mPm.mUserManager.getUserIds(), flags, null,
+                                true);
+                    }
+                    Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage());
+                }
+            }
+        } while (needsUpdating != null && needsUpdating.size() > 0);
+        return resultList;
+    }
+
+    /**
+     * Add a build-in shared library info by given system configuration.
+     */
+    @GuardedBy("mPm.mLock")
+    void addBuiltInSharedLibraryLPw(@NonNull SystemConfig.SharedLibraryEntry entry) {
+        // check if built-in or dynamic library exists
+        if (getSharedLibraryInfo(entry.name, SharedLibraryInfo.VERSION_UNDEFINED) != null) {
+            return;
+        }
+
+        SharedLibraryInfo libraryInfo = new SharedLibraryInfo(entry.filename, null, null,
+                entry.name, SharedLibraryInfo.VERSION_UNDEFINED,
+                SharedLibraryInfo.TYPE_BUILTIN,
+                new VersionedPackage(PLATFORM_PACKAGE_NAME, 0L), null, null,
+                entry.isNative);
+
+        commitSharedLibraryInfoLPw(libraryInfo);
+    }
+
+    /**
+     * Add a shared library info to the system. This is invoked when the package is being added or
+     * scanned.
+     */
+    @GuardedBy("mPm.mLock")
+    void commitSharedLibraryInfoLPw(@NonNull SharedLibraryInfo libraryInfo) {
+        final String name = libraryInfo.getName();
+        WatchedLongSparseArray<SharedLibraryInfo> versionedLib = mSharedLibraries.get(name);
+        if (versionedLib == null) {
+            versionedLib = new WatchedLongSparseArray<>();
+            mSharedLibraries.put(name, versionedLib);
+        }
+        final String declaringPackageName = libraryInfo.getDeclaringPackage().getPackageName();
+        if (libraryInfo.getType() == SharedLibraryInfo.TYPE_STATIC) {
+            mStaticLibsByDeclaringPackage.put(declaringPackageName, versionedLib);
+        }
+        versionedLib.put(libraryInfo.getLongVersion(), libraryInfo);
+    }
+
+    /**
+     * Remove a shared library from the system.
+     */
+    @GuardedBy("mPm.mLock")
+    boolean removeSharedLibraryLPw(@NonNull String libName, long version) {
+        WatchedLongSparseArray<SharedLibraryInfo> versionedLib = mSharedLibraries.get(libName);
+        if (versionedLib == null) {
+            return false;
+        }
+        final int libIdx = versionedLib.indexOfKey(version);
+        if (libIdx < 0) {
+            return false;
+        }
+        SharedLibraryInfo libraryInfo = versionedLib.valueAt(libIdx);
+
+        // Remove the shared library overlays from its dependent packages.
+        for (int currentUserId : mPm.mUserManager.getUserIds()) {
+            final List<VersionedPackage> dependents = mPm.getPackagesUsingSharedLibrary(
+                    libraryInfo, 0, Process.SYSTEM_UID, currentUserId);
+            if (dependents == null) {
+                continue;
+            }
+            for (VersionedPackage dependentPackage : dependents) {
+                final PackageSetting ps = mPm.mSettings.getPackageLPr(
+                        dependentPackage.getPackageName());
+                if (ps != null) {
+                    ps.setOverlayPathsForLibrary(libraryInfo.getName(), null, currentUserId);
+                }
+            }
+        }
+
+        versionedLib.remove(version);
+        if (versionedLib.size() <= 0) {
+            mSharedLibraries.remove(libName);
+            if (libraryInfo.getType() == SharedLibraryInfo.TYPE_STATIC) {
+                mStaticLibsByDeclaringPackage.remove(libraryInfo.getDeclaringPackage()
+                        .getPackageName());
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Dump all shared libraries.
+     */
+    @GuardedBy("mPm.mLock")
+    @Override
+    public void dump(@NonNull PrintWriter pw, @NonNull DumpState dumpState) {
+        final boolean checkin = dumpState.isCheckIn();
+        boolean printedHeader = false;
+        final int numSharedLibraries = mSharedLibraries.size();
+        for (int index = 0; index < numSharedLibraries; index++) {
+            final String libName = mSharedLibraries.keyAt(index);
+            final WatchedLongSparseArray<SharedLibraryInfo> versionedLib =
+                    mSharedLibraries.get(libName);
+            if (versionedLib == null) {
+                continue;
+            }
+            final int versionCount = versionedLib.size();
+            for (int i = 0; i < versionCount; i++) {
+                SharedLibraryInfo libraryInfo = versionedLib.valueAt(i);
+                if (!checkin) {
+                    if (!printedHeader) {
+                        if (dumpState.onTitlePrinted()) {
+                            pw.println();
+                        }
+                        pw.println("Libraries:");
+                        printedHeader = true;
+                    }
+                    pw.print("  ");
+                } else {
+                    pw.print("lib,");
+                }
+                pw.print(libraryInfo.getName());
+                if (libraryInfo.isStatic()) {
+                    pw.print(" version=" + libraryInfo.getLongVersion());
+                }
+                if (!checkin) {
+                    pw.print(" -> ");
+                }
+                if (libraryInfo.getPath() != null) {
+                    if (libraryInfo.isNative()) {
+                        pw.print(" (so) ");
+                    } else {
+                        pw.print(" (jar) ");
+                    }
+                    pw.print(libraryInfo.getPath());
+                } else {
+                    pw.print(" (apk) ");
+                    pw.print(libraryInfo.getPackageName());
+                }
+                pw.println();
+            }
+        }
+    }
+
+    /**
+     * Dump all shared libraries to given proto output stream.
+     */
+    @GuardedBy("mPm.mLock")
+    @Override
+    public void dumpProto(@NonNull ProtoOutputStream proto) {
+        final int count = mSharedLibraries.size();
+        for (int i = 0; i < count; i++) {
+            final String libName = mSharedLibraries.keyAt(i);
+            WatchedLongSparseArray<SharedLibraryInfo> versionedLib =
+                    mSharedLibraries.get(libName);
+            if (versionedLib == null) {
+                continue;
+            }
+            final int versionCount = versionedLib.size();
+            for (int j = 0; j < versionCount; j++) {
+                final SharedLibraryInfo libraryInfo = versionedLib.valueAt(j);
+                final long sharedLibraryToken =
+                        proto.start(PackageServiceDumpProto.SHARED_LIBRARIES);
+                proto.write(PackageServiceDumpProto.SharedLibraryProto.NAME, libraryInfo.getName());
+                final boolean isJar = (libraryInfo.getPath() != null);
+                proto.write(PackageServiceDumpProto.SharedLibraryProto.IS_JAR, isJar);
+                if (isJar) {
+                    proto.write(PackageServiceDumpProto.SharedLibraryProto.PATH,
+                            libraryInfo.getPath());
+                } else {
+                    proto.write(PackageServiceDumpProto.SharedLibraryProto.APK,
+                            libraryInfo.getPackageName());
+                }
+                proto.end(sharedLibraryToken);
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/pm/SharedLibrariesRead.java b/services/core/java/com/android/server/pm/SharedLibrariesRead.java
new file mode 100644
index 0000000..e6f2311
--- /dev/null
+++ b/services/core/java/com/android/server/pm/SharedLibrariesRead.java
@@ -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.server.pm;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.pm.SharedLibraryInfo;
+import android.util.proto.ProtoOutputStream;
+
+import com.android.server.utils.WatchedArrayMap;
+import com.android.server.utils.WatchedLongSparseArray;
+
+import java.io.PrintWriter;
+
+/**
+ * An interface implemented by {@link SharedLibrariesImpl} for {@link Computer} to get current
+ * shared libraries on the device.
+ */
+interface SharedLibrariesRead {
+
+    /**
+     * Returns all shared libraries on the device.
+     *
+     * @return A map of library name to a list of {@link SharedLibraryInfo}s with
+     * different versions.
+     */
+    @NonNull
+    WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>> getAll();
+
+    /**
+     * Given the library name, returns a list of shared libraries on all versions.
+     *
+     * @param libName The library name.
+     * @return A list of shared library info.
+     */
+    @Nullable
+    WatchedLongSparseArray<SharedLibraryInfo> getSharedLibraryInfos(@NonNull String libName);
+
+    /**
+     * Returns the shared library with given library name and version number.
+     *
+     * @param libName The library name.
+     * @param version The library version number.
+     * @return The shared library info.
+     */
+    @Nullable
+    SharedLibraryInfo getSharedLibraryInfo(@NonNull String libName, long version);
+
+    /**
+     * Given the declaring package name, returns a list of static shared libraries on all versions.
+     *
+     * @param declaringPackageName The declaring name of the package.
+     * @return A list of shared library info.
+     */
+    @Nullable
+    WatchedLongSparseArray<SharedLibraryInfo> getStaticLibraryInfos(
+            @NonNull String declaringPackageName);
+
+    /**
+     * Dump all shared libraries.
+     *
+     * @param pw A PrintWriter to dump to.
+     * @param dumpState Including options and states for writing.
+     */
+    void dump(@NonNull PrintWriter pw, @NonNull DumpState dumpState);
+
+    /**
+     * Dump all shared libraries to given proto output stream.
+     * @param proto A proto output stream to dump to.
+     */
+    void dumpProto(@NonNull ProtoOutputStream proto);
+}
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index 3d10b6f..bf7ef1b 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -22,6 +22,7 @@
 import android.app.appsearch.AppSearchManager;
 import android.app.appsearch.AppSearchResult;
 import android.app.appsearch.AppSearchSession;
+import android.app.appsearch.GetByDocumentIdRequest;
 import android.app.appsearch.PackageIdentifier;
 import android.app.appsearch.PutDocumentsRequest;
 import android.app.appsearch.RemoveByDocumentIdRequest;
@@ -820,42 +821,6 @@
                 getPinnedByAnyLauncher, si));
     }
 
-    /**
-     * Find all shortcuts that has id matching {@code ids}.
-     */
-    public void findAllByIds(@NonNull final List<ShortcutInfo> result,
-            @NonNull final Collection<String> ids, @Nullable final Predicate<ShortcutInfo> filter,
-            final int cloneFlag) {
-        findAllByIds(result, ids, filter, cloneFlag, null, 0, /*getPinnedByAnyLauncher=*/ false);
-    }
-
-    /**
-     * Find all shortcuts that has id matching {@code ids}.
-     *
-     * This will also provide a "view" for each launcher -- a non-dynamic shortcut that's not pinned
-     * by the calling launcher will not be included in the result, and also "isPinned" will be
-     * adjusted for the caller too.
-     */
-    public void findAllByIds(@NonNull List<ShortcutInfo> result,
-            @NonNull final Collection<String> ids, @Nullable final Predicate<ShortcutInfo> query,
-            int cloneFlag, @Nullable String callingLauncher, int launcherUserId,
-            boolean getPinnedByAnyLauncher) {
-        if (getPackageInfo().isShadow()) {
-            // Restored and the app not installed yet, so don't return any.
-            return;
-        }
-        final ShortcutService s = mShortcutUser.mService;
-
-        // Set of pinned shortcuts by the calling launcher.
-        final ArraySet<String> pinnedByCallerSet = (callingLauncher == null) ? null
-                : s.getLauncherShortcutsLocked(callingLauncher, getPackageUserId(), launcherUserId)
-                        .getPinnedShortcutIds(getPackageName(), getPackageUserId());
-        for (ShortcutInfo si : mShortcuts.values()) {
-            filter(result, query, cloneFlag, callingLauncher, pinnedByCallerSet,
-                    getPinnedByAnyLauncher, si);
-        }
-    }
-
     private void filter(@NonNull final List<ShortcutInfo> result,
             @Nullable final Predicate<ShortcutInfo> query, final int cloneFlag,
             @Nullable final String callingLauncher,
@@ -2411,6 +2376,25 @@
                 })));
     }
 
+    void getShortcutByIdsAsync(@NonNull final Set<String> ids,
+            @NonNull final Consumer<List<ShortcutInfo>> cb) {
+        if (!isAppSearchEnabled()) {
+            cb.accept(Collections.emptyList());
+            return;
+        }
+        runAsSystem(() -> fromAppSearch().thenAccept(session -> {
+            session.getByDocumentId(new GetByDocumentIdRequest.Builder(getPackageName())
+                    .addIds(ids).build(), mShortcutUser.mExecutor, result -> {
+                    final List<ShortcutInfo> ret = result.getSuccesses().values()
+                            .stream().map(doc ->
+                                    new AppSearchShortcutInfo(doc)
+                                            .toShortcutInfo(mShortcutUser.getUserId()))
+                            .collect(Collectors.toList());
+                    cb.accept(ret);
+                });
+        }));
+    }
+
     private void removeShortcutAsync(@NonNull final String... id) {
         Objects.requireNonNull(id);
         removeShortcutAsync(Arrays.asList(id));
@@ -2444,9 +2428,8 @@
         }
         if (ShortcutService.DEBUG_REBOOT) {
             Slog.d(TAG, "Saving shortcuts async for user=" + mShortcutUser.getUserId()
-                    + " pkg=" + getPackageName() + " ids=["
-                    + shortcuts.stream().map(ShortcutInfo::getId)
-                    .collect(Collectors.joining(",")) + "]");
+                    + " pkg=" + getPackageName() + " ids=" + shortcuts.stream()
+                    .map(ShortcutInfo::getId).collect(Collectors.joining(",", "[", "]")));
         }
         runAsSystem(() -> fromAppSearch().thenAccept(session -> {
             if (shortcuts.isEmpty()) {
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index a482f9a..0a2735cd 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -153,6 +153,7 @@
 import java.util.function.Consumer;
 import java.util.function.Predicate;
 import java.util.regex.Pattern;
+import java.util.stream.Collectors;
 
 /**
  * TODO:
@@ -2957,13 +2958,8 @@
 
             final Predicate<ShortcutInfo> filter = getFilterFromQuery(ids, locusIds, changedSince,
                     componentName, queryFlags, getPinnedByAnyLauncher);
-            if (ids != null && !ids.isEmpty()) {
-                p.findAllByIds(ret, ids, filter, cloneFlag, callingPackage, launcherUserId,
+            p.findAll(ret, filter, cloneFlag, callingPackage, launcherUserId,
                         getPinnedByAnyLauncher);
-            } else {
-                p.findAll(ret, filter, cloneFlag, callingPackage, launcherUserId,
-                        getPinnedByAnyLauncher);
-            }
         }
 
         private Predicate<ShortcutInfo> getFilterFromQuery(@Nullable ArraySet<String> ids,
@@ -3010,6 +3006,51 @@
         }
 
         @Override
+        public void getShortcutsAsync(int launcherUserId,
+                @NonNull String callingPackage, long changedSince,
+                @Nullable String packageName, @Nullable List<String> shortcutIds,
+                @Nullable List<LocusId> locusIds, @Nullable ComponentName componentName,
+                int queryFlags, int userId, int callingPid, int callingUid,
+                @NonNull AndroidFuture<List<ShortcutInfo>> cb) {
+            final List<ShortcutInfo> ret = getShortcuts(launcherUserId, callingPackage,
+                    changedSince, packageName, shortcutIds, locusIds, componentName, queryFlags,
+                    userId, callingPid, callingUid);
+            if (shortcutIds == null || packageName == null || ret.size() >= shortcutIds.size()) {
+                // skip persistence layer if not querying by id in a specific package or all
+                // shortcuts have already been found.
+                cb.complete(ret);
+                return;
+            }
+            final ShortcutPackage p;
+            synchronized (mLock) {
+                p = getUserShortcutsLocked(userId).getPackageShortcutsIfExists(packageName);
+            }
+            if (p == null) {
+                cb.complete(ret);
+                return; // Bail-out directly if package doesn't exist.
+            }
+            // fetch remaining shortcuts from persistence layer
+            final ArraySet<String> ids = new ArraySet<>(shortcutIds);
+            // remove the ids that are already fetched
+            ret.stream().map(ShortcutInfo::getId).collect(Collectors.toList()).forEach(ids::remove);
+
+            int flags = ShortcutInfo.CLONE_REMOVE_FOR_LAUNCHER;
+            if ((queryFlags & ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY) != 0) {
+                flags = ShortcutInfo.CLONE_REMOVE_NON_KEY_INFO;
+            } else if ((queryFlags & ShortcutQuery.FLAG_GET_PERSONS_DATA) != 0) {
+                flags &= ~ShortcutInfo.CLONE_REMOVE_PERSON;
+            }
+            final int cloneFlag = flags;
+
+            p.getShortcutByIdsAsync(ids, shortcuts -> {
+                if (shortcuts != null) {
+                    shortcuts.stream().map(si -> si.clone(cloneFlag)).forEach(ret::add);
+                }
+                cb.complete(ret);
+            });
+        }
+
+        @Override
         public boolean isPinnedByCaller(int launcherUserId, @NonNull String callingPackage,
                 @NonNull String packageName, @NonNull String shortcutId, int userId) {
             Preconditions.checkStringNotEmpty(packageName, "packageName");
@@ -3047,12 +3088,32 @@
             }
 
             final ArrayList<ShortcutInfo> list = new ArrayList<>(1);
-            p.findAllByIds(list, Collections.singletonList(shortcutId),
-                    (ShortcutInfo si) -> shortcutId.equals(si.getId()),
+            p.findAll(list, (ShortcutInfo si) -> shortcutId.equals(si.getId()),
                     /* clone flags=*/ 0, callingPackage, launcherUserId, getPinnedByAnyLauncher);
             return list.size() == 0 ? null : list.get(0);
         }
 
+        private void getShortcutInfoAsync(
+                int launcherUserId, @NonNull String packageName, @NonNull String shortcutId,
+                int userId, @NonNull Consumer<ShortcutInfo> cb) {
+            Preconditions.checkStringNotEmpty(packageName, "packageName");
+            Preconditions.checkStringNotEmpty(shortcutId, "shortcutId");
+
+            throwIfUserLockedL(userId);
+            throwIfUserLockedL(launcherUserId);
+
+            final ShortcutPackage p;
+            synchronized (mLock) {
+                p = getUserShortcutsLocked(userId).getPackageShortcutsIfExists(packageName);
+            }
+            if (p == null) {
+                cb.accept(null);
+                return;
+            }
+            p.getShortcutByIdsAsync(Collections.singleton(shortcutId), shortcuts ->
+                    cb.accept(shortcuts == null || shortcuts.isEmpty() ? null : shortcuts.get(0)));
+        }
+
         @Override
         public void pinShortcuts(int launcherUserId,
                 @NonNull String callingPackage, @NonNull String packageName,
@@ -3237,6 +3298,48 @@
         }
 
         @Override
+        public void createShortcutIntentsAsync(int launcherUserId,
+                @NonNull String callingPackage, @NonNull String packageName,
+                @NonNull String shortcutId, int userId, int callingPid,
+                int callingUid, @NonNull AndroidFuture<Intent[]> cb) {
+            // Calling permission must be checked by LauncherAppsImpl.
+            Preconditions.checkStringNotEmpty(packageName, "packageName can't be empty");
+            Preconditions.checkStringNotEmpty(shortcutId, "shortcutId can't be empty");
+
+            // Check in memory shortcut first
+            synchronized (mLock) {
+                throwIfUserLockedL(userId);
+                throwIfUserLockedL(launcherUserId);
+
+                getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
+                        .attemptToRestoreIfNeededAndSave();
+
+                final boolean getPinnedByAnyLauncher =
+                        canSeeAnyPinnedShortcut(callingPackage, launcherUserId,
+                                callingPid, callingUid);
+
+                // Make sure the shortcut is actually visible to the launcher.
+                final ShortcutInfo si = getShortcutInfoLocked(
+                        launcherUserId, callingPackage, packageName, shortcutId, userId,
+                        getPinnedByAnyLauncher);
+                if (si != null) {
+                    if (!si.isEnabled() || !(si.isAlive() || getPinnedByAnyLauncher)) {
+                        Log.e(TAG, "Shortcut " + shortcutId + " does not exist or disabled");
+                        cb.complete(null);
+                        return;
+                    }
+                    cb.complete(si.getIntents());
+                    return;
+                }
+            }
+
+            // Otherwise check persisted shortcuts
+            getShortcutInfoAsync(launcherUserId, packageName, shortcutId, userId, si -> {
+                cb.complete(si == null ? null : si.getIntents());
+            });
+        }
+
+        @Override
         public void addListener(@NonNull ShortcutChangeListener listener) {
             synchronized (mLock) {
                 mListeners.add(Objects.requireNonNull(listener));
@@ -3326,23 +3429,68 @@
                 }
 
                 final ShortcutInfo shortcutInfo = p.findShortcutById(shortcutId);
-                if (shortcutInfo == null || !shortcutInfo.hasIconFile()) {
+                if (shortcutInfo == null) {
                     return null;
                 }
-                final String path = mShortcutBitmapSaver.getBitmapPathMayWaitLocked(shortcutInfo);
-                if (path == null) {
-                    Slog.w(TAG, "null bitmap detected in getShortcutIconFd()");
-                    return null;
+                return getShortcutIconParcelFileDescriptor(shortcutInfo);
+            }
+        }
+
+        @Override
+        public void getShortcutIconFdAsync(int launcherUserId, @NonNull String callingPackage,
+                @NonNull String packageName, @NonNull String shortcutId, int userId,
+                @NonNull AndroidFuture<ParcelFileDescriptor> cb) {
+            Objects.requireNonNull(callingPackage, "callingPackage");
+            Objects.requireNonNull(packageName, "packageName");
+            Objects.requireNonNull(shortcutId, "shortcutId");
+
+            // Checks shortcuts in memory first
+            synchronized (mLock) {
+                throwIfUserLockedL(userId);
+                throwIfUserLockedL(launcherUserId);
+
+                getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
+                        .attemptToRestoreIfNeededAndSave();
+
+                final ShortcutPackage p = getUserShortcutsLocked(userId)
+                        .getPackageShortcutsIfExists(packageName);
+                if (p == null) {
+                    cb.complete(null);
+                    return;
                 }
-                try {
-                    return ParcelFileDescriptor.open(
-                            new File(path),
-                            ParcelFileDescriptor.MODE_READ_ONLY);
-                } catch (FileNotFoundException e) {
-                    Slog.e(TAG, "Icon file not found: " + path);
-                    return null;
+
+                final ShortcutInfo shortcutInfo = p.findShortcutById(shortcutId);
+                if (shortcutInfo != null) {
+                    cb.complete(getShortcutIconParcelFileDescriptor(shortcutInfo));
+                    return;
                 }
             }
+
+            // Otherwise check persisted shortcuts
+            getShortcutInfoAsync(launcherUserId, packageName, shortcutId, userId, si -> {
+                cb.complete(getShortcutIconParcelFileDescriptor(si));
+            });
+        }
+
+        @Nullable
+        private ParcelFileDescriptor getShortcutIconParcelFileDescriptor(
+                @NonNull final ShortcutInfo shortcutInfo) {
+            if (!shortcutInfo.hasIconFile()) {
+                return null;
+            }
+            final String path = mShortcutBitmapSaver.getBitmapPathMayWaitLocked(shortcutInfo);
+            if (path == null) {
+                Slog.w(TAG, "null bitmap detected in getShortcutIconFd()");
+                return null;
+            }
+            try {
+                return ParcelFileDescriptor.open(
+                        new File(path),
+                        ParcelFileDescriptor.MODE_READ_ONLY);
+            } catch (FileNotFoundException e) {
+                Slog.e(TAG, "Icon file not found: " + path);
+                return null;
+            }
         }
 
         @Override
@@ -3366,34 +3514,82 @@
                 }
 
                 final ShortcutInfo shortcutInfo = p.findShortcutById(shortcutId);
-                if (shortcutInfo == null || !shortcutInfo.hasIconUri()) {
+                if (shortcutInfo == null) {
                     return null;
                 }
-                String uri = shortcutInfo.getIconUri();
-                if (uri == null) {
-                    Slog.w(TAG, "null uri detected in getShortcutIconUri()");
-                    return null;
+                return getShortcutIconUriInternal(launcherUserId, launcherPackage,
+                        packageName, shortcutInfo, userId);
+            }
+        }
+
+        @Override
+        public void getShortcutIconUriAsync(int launcherUserId, @NonNull String launcherPackage,
+                @NonNull String packageName, @NonNull String shortcutId, int userId,
+                @NonNull AndroidFuture<String> cb) {
+            Objects.requireNonNull(launcherPackage, "launcherPackage");
+            Objects.requireNonNull(packageName, "packageName");
+            Objects.requireNonNull(shortcutId, "shortcutId");
+
+            // Checks shortcuts in memory first
+            synchronized (mLock) {
+                throwIfUserLockedL(userId);
+                throwIfUserLockedL(launcherUserId);
+
+                getLauncherShortcutsLocked(launcherPackage, userId, launcherUserId)
+                        .attemptToRestoreIfNeededAndSave();
+
+                final ShortcutPackage p = getUserShortcutsLocked(userId)
+                        .getPackageShortcutsIfExists(packageName);
+                if (p == null) {
+                    cb.complete(null);
+                    return;
                 }
 
-                final long token = Binder.clearCallingIdentity();
-                try {
-                    int packageUid = mPackageManagerInternal.getPackageUid(packageName,
-                            PackageManager.MATCH_DIRECT_BOOT_AUTO, userId);
-                    // Grant read uri permission to the caller on behalf of the shortcut owner. All
-                    // granted permissions are revoked when the default launcher changes, or when
-                    // device is rebooted.
-                    mUriGrantsManager.grantUriPermissionFromOwner(mUriPermissionOwner, packageUid,
-                            launcherPackage, Uri.parse(uri), Intent.FLAG_GRANT_READ_URI_PERMISSION,
-                            userId, launcherUserId);
-                } catch (Exception e) {
-                    Slog.e(TAG, "Failed to grant uri access to " + launcherPackage + " for " + uri,
-                            e);
-                    uri = null;
-                } finally {
-                    Binder.restoreCallingIdentity(token);
+                final ShortcutInfo shortcutInfo = p.findShortcutById(shortcutId);
+                if (shortcutInfo != null) {
+                    cb.complete(getShortcutIconUriInternal(launcherUserId, launcherPackage,
+                            packageName, shortcutInfo, userId));
+                    return;
                 }
-                return uri;
             }
+
+            // Otherwise check persisted shortcuts
+            getShortcutInfoAsync(launcherUserId, packageName, shortcutId, userId, si -> {
+                cb.complete(getShortcutIconUriInternal(launcherUserId, launcherPackage,
+                        packageName, si, userId));
+            });
+        }
+
+        private String getShortcutIconUriInternal(int launcherUserId,
+                @NonNull String launcherPackage, @NonNull String packageName,
+                @NonNull ShortcutInfo shortcutInfo, int userId) {
+            if (!shortcutInfo.hasIconUri()) {
+                return null;
+            }
+            String uri = shortcutInfo.getIconUri();
+            if (uri == null) {
+                Slog.w(TAG, "null uri detected in getShortcutIconUri()");
+                return null;
+            }
+
+            final long token = Binder.clearCallingIdentity();
+            try {
+                int packageUid = mPackageManagerInternal.getPackageUid(packageName,
+                        PackageManager.MATCH_DIRECT_BOOT_AUTO, userId);
+                // Grant read uri permission to the caller on behalf of the shortcut owner. All
+                // granted permissions are revoked when the default launcher changes, or when
+                // device is rebooted.
+                mUriGrantsManager.grantUriPermissionFromOwner(mUriPermissionOwner, packageUid,
+                        launcherPackage, Uri.parse(uri), Intent.FLAG_GRANT_READ_URI_PERMISSION,
+                        userId, launcherUserId);
+            } catch (Exception e) {
+                Slog.e(TAG, "Failed to grant uri access to " + launcherPackage + " for " + uri,
+                        e);
+                uri = null;
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+            return uri;
         }
 
         @Override
@@ -5154,7 +5350,7 @@
         }
 
         List<ShortcutInfo> result = new ArrayList<>();
-        ps.findAllByIds(result, resultIds, (ShortcutInfo si) -> resultIds.contains(si.getId()),
+        ps.findAll(result, (ShortcutInfo si) -> resultIds.contains(si.getId()),
                 ShortcutInfo.CLONE_REMOVE_NON_KEY_INFO);
         return result;
     }
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 9cb8863..8a6ef6b 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -32,7 +32,7 @@
 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.PackageInstaller.SessionInfo.SessionErrorCode;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.StagedApexInfo;
@@ -129,7 +129,7 @@
         boolean containsApkSession();
         boolean containsApexSession();
         void setSessionReady();
-        void setSessionFailed(@StagedSessionErrorCode int errorCode, String errorMessage);
+        void setSessionFailed(@SessionErrorCode int errorCode, String errorMessage);
         void setSessionApplied();
         void installSession(IntentSender statusReceiver);
         boolean hasParentSessionId();
@@ -932,9 +932,7 @@
                     info.diskImagePath = ai.modulePath;
                     info.versionCode = ai.versionCode;
                     info.versionName = ai.versionName;
-                    info.hasBootClassPathJars = ai.hasBootClassPathJars;
-                    info.hasDex2OatBootClassPathJars = ai.hasDex2OatBootClassPathJars;
-                    info.hasSystemServerClassPathJars = ai.hasSystemServerClassPathJars;
+                    info.hasClassPathJars = ai.hasClassPathJars;
                     return info;
                 }
             }
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index 6c1ef2e..b15e495 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -198,6 +198,7 @@
     private static final Set<String> SENSORS_PERMISSIONS = new ArraySet<>();
     static {
         SENSORS_PERMISSIONS.add(Manifest.permission.BODY_SENSORS);
+        SENSORS_PERMISSIONS.add(Manifest.permission.BODY_SENSORS_BACKGROUND);
     }
 
     private static final Set<String> STORAGE_PERMISSIONS = new ArraySet<>();
@@ -809,7 +810,7 @@
             } else {
                 grantPermissionsToSystemPackage(pm,
                     getDefaultSystemHandlerActivityPackage(pm, ACTION_TRACK, userId), userId,
-                    SENSORS_PERMISSIONS, ALWAYS_LOCATION_PERMISSIONS);
+                    SENSORS_PERMISSIONS);
             }
         }
 
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 0958bcb..a3b6b82 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -1252,7 +1252,8 @@
                 if (op < 0) {
                     // Bg location is one-off runtime modifier permission and has no app op
                     if (sPlatformPermissions.contains(permission)
-                            && !Manifest.permission.ACCESS_BACKGROUND_LOCATION.equals(permission)) {
+                            && !Manifest.permission.ACCESS_BACKGROUND_LOCATION.equals(permission)
+                            && !Manifest.permission.BODY_SENSORS_BACKGROUND.equals(permission)) {
                         Slog.wtf(LOG_TAG, "Platform runtime permission " + permission
                                 + " with no app op defined!");
                     }
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
index d1b9938..c9fd122 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
@@ -23,6 +23,7 @@
 import static android.app.AppOpsManager.MODE_IGNORED;
 import static android.content.pm.PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_AUTO_REVOKED;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_ROLE;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_ONE_TIME;
@@ -108,6 +109,7 @@
 import android.util.EventLog;
 import android.util.IntArray;
 import android.util.Log;
+import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
@@ -196,6 +198,9 @@
     /** All nearby devices permissions */
     private static final List<String> NEARBY_DEVICES_PERMISSIONS = new ArrayList<>();
 
+    // TODO: This is a placeholder. Replace with actual implementation
+    private static final List<String> NOTIFICATION_PERMISSIONS = new ArrayList<>();
+
     /**
      * All permissions that should be granted with the REVOKE_WHEN_REQUESTED flag, if they are
      * implicitly added to a package
@@ -4636,23 +4641,231 @@
         return true;
     }
 
-    private void onPackageInstalledInternal(@NonNull AndroidPackage pkg, int previousAppId,
-            @NonNull PermissionManagerServiceInternal.PackageInstalledParams params,
-            @UserIdInt int[] userIds) {
-        // If previousAppId is not Process.INVALID_UID, the package is performing a migration out
-        // of a shared user group. Operations we need to do before calling updatePermissions():
-        // - Retrieve the original uid permission state and create a copy of it as the new app's
-        //   uid state. The new permission state will be properly updated in updatePermissions().
-        // - Remove the app from the original shared user group. Other apps in the shared
-        //   user group will perceive as if the original app is uninstalled.
-        if (previousAppId != Process.INVALID_UID) {
-            final PackageStateInternal ps =
-                    mPackageManagerInt.getPackageStateInternal(pkg.getPackageName());
+    private boolean isEffectivelyGranted(PermissionState state) {
+        final int flags = state.getFlags();
+        final int denyMask = FLAG_PERMISSION_REVIEW_REQUIRED
+                | FLAG_PERMISSION_REVOKED_COMPAT
+                | FLAG_PERMISSION_ONE_TIME;
+
+        if ((flags & FLAG_PERMISSION_SYSTEM_FIXED) != 0) {
+            return true;
+        } else if ((flags & FLAG_PERMISSION_POLICY_FIXED) != 0) {
+            return (flags & FLAG_PERMISSION_REVOKED_COMPAT) == 0 && state.isGranted();
+        } else if ((flags & denyMask) != 0) {
+            return false;
+        } else {
+            return state.isGranted();
+        }
+    }
+
+    /**
+     * Merge srcState into destState. Return [granted, flags].
+     */
+    private Pair<Boolean, Integer> mergePermissionState(int appId,
+            PermissionState srcState, PermissionState destState) {
+        // This merging logic prioritizes the shared permission state (destState) over
+        // the current package's state (srcState), because an uninstallation of a previously
+        // unrelated app (the updated system app) should not affect the functionality of
+        // existing apps (other apps in the shared UID group).
+
+        final int userSettableMask = FLAG_PERMISSION_USER_SET
+                | FLAG_PERMISSION_USER_FIXED
+                | FLAG_PERMISSION_SELECTED_LOCATION_ACCURACY;
+
+        final int defaultGrantMask = FLAG_PERMISSION_GRANTED_BY_DEFAULT
+                | FLAG_PERMISSION_GRANTED_BY_ROLE;
+
+        final int priorityFixedMask = FLAG_PERMISSION_SYSTEM_FIXED
+                | FLAG_PERMISSION_POLICY_FIXED;
+
+        final int priorityMask = defaultGrantMask | priorityFixedMask;
+
+        final int destFlags = destState.getFlags();
+        final boolean destIsGranted = isEffectivelyGranted(destState);
+
+        final int srcFlags = srcState.getFlags();
+        final boolean srcIsGranted = isEffectivelyGranted(srcState);
+
+        final int combinedFlags = destFlags | srcFlags;
+
+        /* Merge flags */
+
+        int newFlags = 0;
+
+        // Inherit user set flags only from dest as we want to preserve the
+        // user preference of destState, not the one of the current package.
+        newFlags |= (destFlags & userSettableMask);
+
+        // Inherit all exempt flags
+        newFlags |= (combinedFlags & FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT);
+        // If no exempt flags are set, set APPLY_RESTRICTION
+        if ((newFlags & FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) == 0) {
+            newFlags |= FLAG_PERMISSION_APPLY_RESTRICTION;
+        }
+
+        // Inherit all priority flags
+        newFlags |= (combinedFlags & priorityMask);
+
+        // If no priority flags are set, inherit REVOKE_WHEN_REQUESTED
+        if ((combinedFlags & priorityMask) == 0) {
+            newFlags |= (combinedFlags & FLAG_PERMISSION_REVOKE_WHEN_REQUESTED);
+        }
+
+        // Handle REVIEW_REQUIRED
+        if ((newFlags & priorityFixedMask) == 0) {
+            if (NOTIFICATION_PERMISSIONS.contains(srcState.getName())) {
+                // For notification permissions, inherit from both states
+                // if no priority FIXED flags are set
+                newFlags |= (combinedFlags & FLAG_PERMISSION_REVIEW_REQUIRED);
+            } else if ((newFlags & priorityMask) == 0) {
+                // Else inherit from destState if no priority flags are set
+                newFlags |= (destFlags & FLAG_PERMISSION_REVIEW_REQUIRED);
+            }
+        }
+
+        /* Determine effective grant state */
+
+        final boolean effectivelyGranted;
+        if ((newFlags & FLAG_PERMISSION_SYSTEM_FIXED) != 0) {
+            effectivelyGranted = true;
+        } else if ((destFlags & FLAG_PERMISSION_POLICY_FIXED) != 0) {
+            // If this flag comes from destState, preserve its state
+            effectivelyGranted = destIsGranted;
+        } else if ((srcFlags & FLAG_PERMISSION_POLICY_FIXED) != 0) {
+            effectivelyGranted = destIsGranted || srcIsGranted;
+            // If this flag comes from srcState, preserve flag only if
+            // there is no conflict
+            if (destIsGranted != srcIsGranted) {
+                newFlags &= ~FLAG_PERMISSION_POLICY_FIXED;
+            }
+        } else if ((destFlags & defaultGrantMask) != 0) {
+            // If a permission state has default grant flags and is not
+            // granted, this meant user has overridden the grant state.
+            // Respect the user's preference on destState.
+            // Due to this reason, if this flag comes from destState,
+            // preserve its state
+            effectivelyGranted = destIsGranted;
+        } else if ((srcFlags & defaultGrantMask) != 0) {
+            effectivelyGranted = destIsGranted || srcIsGranted;
+        } else if ((destFlags & FLAG_PERMISSION_REVOKE_WHEN_REQUESTED) != 0) {
+            // Similar reason to defaultGrantMask, if this flag comes
+            // from destState, preserve its state
+            effectivelyGranted = destIsGranted;
+        } else if ((srcFlags & FLAG_PERMISSION_REVOKE_WHEN_REQUESTED) != 0) {
+            effectivelyGranted = destIsGranted || srcIsGranted;
+            // If this flag comes from srcState, remove this flag if
+            // destState is already granted to prevent revocation.
+            if (destIsGranted) {
+                newFlags &= ~FLAG_PERMISSION_REVOKE_WHEN_REQUESTED;
+            }
+        } else {
+            // If still not determined, fallback to destState.
+            effectivelyGranted = destIsGranted;
+        }
+
+        /* Post-processing / fix ups */
+
+        if (!effectivelyGranted) {
+            // If not effectively granted, inherit AUTO_REVOKED
+            newFlags |= (combinedFlags & FLAG_PERMISSION_AUTO_REVOKED);
+
+            // REVOKE_WHEN_REQUESTED make no sense when denied
+            newFlags &= ~FLAG_PERMISSION_REVOKE_WHEN_REQUESTED;
+        } else {
+            // REVIEW_REQUIRED make no sense when granted
+            newFlags &= ~FLAG_PERMISSION_REVIEW_REQUIRED;
+        }
+
+        if (effectivelyGranted != destIsGranted) {
+            // Remove user set flags if state changes
+            newFlags &= ~userSettableMask;
+        }
+
+        // Fix permission state based on targetSdk of the shared UID
+        final boolean newGrantState;
+        if (!effectivelyGranted && isPermissionSplitFromNonRuntime(
+                srcState.getName(),
+                mPackageManagerInt.getUidTargetSdkVersion(appId))) {
+            // Even though effectively denied, it has to be set to granted
+            // for backwards compatibility
+            newFlags |= FLAG_PERMISSION_REVOKED_COMPAT;
+            newGrantState = true;
+        } else {
+            // Either it's effectively granted, or it targets a high enough API level
+            // to handle this permission properly
+            newGrantState = effectivelyGranted;
+        }
+
+        return new Pair<>(newGrantState, newFlags);
+    }
+
+    /**
+     * This method handles permission migration of packages leaving/joining shared UID
+     */
+    private void handleAppIdMigration(@NonNull AndroidPackage pkg, int previousAppId) {
+        final PackageStateInternal ps =
+                mPackageManagerInt.getPackageStateInternal(pkg.getPackageName());
+
+        if (ps.getSharedUser() != null) {
+            // The package is joining a shared user group. This can only happen when a system
+            // app left shared UID with an update, and then the update is uninstalled.
+            // If no apps remain in its original shared UID group, clone the current
+            // permission state to the shared appId; or else, merge the current permission
+            // state into the shared UID state.
+
+            synchronized (mLock) {
+                for (final int userId : getAllUserIds()) {
+                    final UserPermissionState userState = mState.getOrCreateUserState(userId);
+
+                    // This is the permission state the package was using
+                    final UidPermissionState uidState = userState.getUidState(previousAppId);
+                    if (uidState == null) {
+                        continue;
+                    }
+
+                    // This is the shared UID permission state the package wants to join
+                    final UidPermissionState sharedUidState = userState.getUidState(ps.getAppId());
+                    if (sharedUidState == null) {
+                        // No apps remain in the shared UID group, clone permissions
+                        userState.createUidStateWithExisting(ps.getAppId(), uidState);
+                    } else {
+                        final List<PermissionState> states = uidState.getPermissionStates();
+                        final int count = states.size();
+                        for (int i = 0; i < count; ++i) {
+                            final PermissionState srcState = states.get(i);
+                            final PermissionState destState =
+                                    sharedUidState.getPermissionState(srcState.getName());
+                            if (destState != null) {
+                                // Merge the 2 permission states
+                                Pair<Boolean, Integer> newState =
+                                        mergePermissionState(ps.getAppId(), srcState, destState);
+                                sharedUidState.putPermissionState(srcState.getPermission(),
+                                        newState.first, newState.second);
+                            } else {
+                                // Simply copy the permission state over
+                                sharedUidState.putPermissionState(srcState.getPermission(),
+                                        srcState.isGranted(), srcState.getFlags());
+                            }
+                        }
+                    }
+
+                    // Remove permissions for the previous appId
+                    userState.removeUidState(previousAppId);
+                }
+            }
+        } else {
+            // The package is migrating out of a shared user group.
+            // Operations we need to do before calling updatePermissions():
+            // - Retrieve the original uid permission state and create a copy of it as the
+            //   new app's uid state. The new permission state will be properly updated in
+            //   updatePermissions().
+            // - Remove the app from the original shared user group. Other apps in the shared
+            //   user group will perceive as if the original app is uninstalled.
+
             final List<AndroidPackage> origSharedUserPackages =
                     mPackageManagerInt.getPackagesForAppId(previousAppId);
 
             synchronized (mLock) {
-                // All users are affected
                 for (final int userId : getAllUserIds()) {
                     // Retrieve the original uid state
                     final UserPermissionState userState = mState.getUserState(userId);
@@ -4679,6 +4892,14 @@
                 }
             }
         }
+    }
+
+    private void onPackageInstalledInternal(@NonNull AndroidPackage pkg, int previousAppId,
+            @NonNull PermissionManagerServiceInternal.PackageInstalledParams params,
+            @UserIdInt int[] userIds) {
+        if (previousAppId != Process.INVALID_UID) {
+            handleAppIdMigration(pkg, previousAppId);
+        }
         updatePermissions(pkg.getPackageName(), pkg);
         for (final int userId : userIds) {
             addAllowlistedRestrictedPermissionsInternal(pkg,
diff --git a/services/core/java/com/android/server/pm/pkg/PackageState.java b/services/core/java/com/android/server/pm/pkg/PackageState.java
index 34575e0..f5ee8d9 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageState.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageState.java
@@ -100,12 +100,6 @@
     String getCpuAbiOverride();
 
     /**
-     * In epoch milliseconds. The timestamp of the first install of the particular app on the
-     * device, surviving past app updates. This does not survive full uninstalls + reinstalls.
-     */
-    long getFirstInstallTime();
-
-    /**
      * In epoch milliseconds. The last modified time of the file directory which houses the app
      * APKs. Only updated on package update; does not track realtime modifications.
      */
diff --git a/services/core/java/com/android/server/pm/pkg/PackageStateImpl.java b/services/core/java/com/android/server/pm/pkg/PackageStateImpl.java
index f5e498d..a5d399e 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageStateImpl.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageStateImpl.java
@@ -115,7 +115,6 @@
     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;
@@ -166,7 +165,6 @@
         mAppId = pkgState.getAppId();
         mCategoryOverride = pkgState.getCategoryOverride();
         mCpuAbiOverride = pkgState.getCpuAbiOverride();
-        mFirstInstallTime = pkgState.getFirstInstallTime();
         mLastModifiedTime = pkgState.getLastModifiedTime();
         mLastUpdateTime = pkgState.getLastUpdateTime();
         mLongVersionCode = pkgState.getVersionCode();
@@ -341,6 +339,7 @@
         private final int mUninstallReason;
         @Nullable
         private final String mSplashScreenTheme;
+        private final long mFirstInstallTime;
 
         private UserStateImpl(@NonNull PackageUserState userState) {
             mCeDataInode = userState.getCeDataInode();
@@ -362,6 +361,7 @@
             setBoolean(Booleans.STOPPED, userState.isStopped());
             setBoolean(Booleans.SUSPENDED, userState.isSuspended());
             setBoolean(Booleans.VIRTUAL_PRELOAD, userState.isVirtualPreload());
+            mFirstInstallTime = userState.getFirstInstallTime();
         }
 
         @Override
@@ -505,16 +505,21 @@
         }
 
         @DataClass.Generated.Member
+        public long getFirstInstallTime() {
+            return mFirstInstallTime;
+        }
+
+        @DataClass.Generated.Member
         public @NonNull UserStateImpl setBooleans( int value) {
             mBooleans = value;
             return this;
         }
 
         @DataClass.Generated(
-                time = 1637977288540L,
+                time = 1640209608883L,
                 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\nprivate final @android.annotation.Nullable java.lang.String mSplashScreenTheme\npublic static  com.android.server.pm.pkg.PackageUserState copy(com.android.server.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()\npublic @java.lang.Override boolean isComponentEnabled(java.lang.String)\npublic @java.lang.Override boolean isComponentDisabled(java.lang.String)\npublic @java.lang.Override android.content.pm.overlay.OverlayPaths getAllOverlayPaths()\nclass UserStateImpl extends java.lang.Object implements [com.android.server.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)")
+                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\nprivate final @android.annotation.Nullable java.lang.String mSplashScreenTheme\nprivate final  long mFirstInstallTime\npublic static  com.android.server.pm.pkg.PackageUserState copy(com.android.server.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()\npublic @java.lang.Override boolean isComponentEnabled(java.lang.String)\npublic @java.lang.Override boolean isComponentDisabled(java.lang.String)\npublic @java.lang.Override android.content.pm.overlay.OverlayPaths getAllOverlayPaths()\nclass UserStateImpl extends java.lang.Object implements [com.android.server.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() {}
 
@@ -575,11 +580,6 @@
     }
 
     @DataClass.Generated.Member
-    public long getFirstInstallTime() {
-        return mFirstInstallTime;
-    }
-
-    @DataClass.Generated.Member
     public long getLastModifiedTime() {
         return mLastModifiedTime;
     }
@@ -671,10 +671,10 @@
     }
 
     @DataClass.Generated(
-            time = 1637977288579L,
+            time = 1640209608912L,
             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[] mUsesSdkLibraries\nprivate final @android.annotation.NonNull long[] mUsesSdkLibrariesVersionsMajor\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.NonNull long[] mLastPackageUsageTime\nprivate final @android.annotation.NonNull android.content.pm.SigningInfo mSigningInfo\nprivate final @android.annotation.NonNull android.util.SparseArray<com.android.server.pm.pkg.PackageUserState> mUserStates\npublic static  com.android.server.pm.pkg.PackageState copy(com.android.server.pm.pkg.PackageStateInternal)\nprivate  void setBoolean(int,boolean)\nprivate  boolean getBoolean(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()\npublic @java.lang.Override long getVersionCode()\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)")
+            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 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[] mUsesSdkLibraries\nprivate final @android.annotation.NonNull long[] mUsesSdkLibrariesVersionsMajor\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.NonNull long[] mLastPackageUsageTime\nprivate final @android.annotation.NonNull android.content.pm.SigningInfo mSigningInfo\nprivate final @android.annotation.NonNull android.util.SparseArray<com.android.server.pm.pkg.PackageUserState> mUserStates\npublic static  com.android.server.pm.pkg.PackageState copy(com.android.server.pm.pkg.PackageStateInternal)\nprivate  void setBoolean(int,boolean)\nprivate  boolean getBoolean(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()\npublic @java.lang.Override long getVersionCode()\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() {}
 
diff --git a/services/core/java/com/android/server/pm/pkg/PackageStateInternal.java b/services/core/java/com/android/server/pm/pkg/PackageStateInternal.java
index 5460afa..56f62ab 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageStateInternal.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageStateInternal.java
@@ -23,6 +23,7 @@
 import android.util.SparseArray;
 
 import com.android.server.pm.InstallSource;
+import com.android.server.pm.PackageKeySetData;
 import com.android.server.pm.SharedUserSetting;
 import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.permission.LegacyPermissionState;
@@ -82,4 +83,7 @@
     String getPathString();
 
     float getLoadingProgress();
+
+    @NonNull
+    PackageKeySetData getKeySetData();
 }
diff --git a/services/core/java/com/android/server/pm/pkg/PackageStateUtils.java b/services/core/java/com/android/server/pm/pkg/PackageStateUtils.java
index 09b9d31..6c8e0b7 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageStateUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageStateUtils.java
@@ -22,6 +22,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.parsing.component.ParsedMainComponent;
 import android.content.pm.pkg.PackageUserStateUtils;
+import android.util.SparseArray;
 
 import com.android.server.pm.parsing.pkg.AndroidPackage;
 
@@ -75,4 +76,23 @@
         return PackageUserStateUtils.isMatch(userState, packageState.isSystem(),
                 pkg.isEnabled(), component, flags);
     }
+
+    /**
+     * Return the earliest non-zero first-install timestamp of an installed app among all the users,
+     * unless none of the users have a non-zero first-install timestamp. In that case, return 0.
+     */
+    public static long getEarliestFirstInstallTime(
+            @Nullable SparseArray<? extends PackageUserStateInternal> userStatesInternal) {
+        if (userStatesInternal == null || userStatesInternal.size() == 0) {
+            return 0;
+        }
+        long earliestFirstInstallTime = Long.MAX_VALUE;
+        for (int i = 0; i < userStatesInternal.size(); i++) {
+            final long firstInstallTime = userStatesInternal.valueAt(i).getFirstInstallTime();
+            if (firstInstallTime != 0 && firstInstallTime < earliestFirstInstallTime) {
+                earliestFirstInstallTime = firstInstallTime;
+            }
+        }
+        return earliestFirstInstallTime == Long.MAX_VALUE ? 0 : earliestFirstInstallTime;
+    }
 }
diff --git a/services/core/java/com/android/server/pm/pkg/PackageUserState.java b/services/core/java/com/android/server/pm/pkg/PackageUserState.java
index 147edf7..03b1692 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageUserState.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageUserState.java
@@ -150,4 +150,13 @@
      */
     @Nullable
     String getSplashScreenTheme();
+
+    /**
+     * In epoch milliseconds. The timestamp of the first install of the app of the particular user
+     * on the device, surviving past app updates. Different users might have a different first
+     * install time.
+     *
+     * This does not survive full removal of the app (i.e., uninstalls for all users).
+     */
+    long getFirstInstallTime();
 }
diff --git a/services/core/java/com/android/server/pm/pkg/PackageUserStateDefault.java b/services/core/java/com/android/server/pm/pkg/PackageUserStateDefault.java
index 481c3e0..73c86c7 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageUserStateDefault.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageUserStateDefault.java
@@ -134,6 +134,11 @@
     }
 
     @Override
+    public long getFirstInstallTime() {
+        return 0;
+    }
+
+    @Override
     public boolean isComponentEnabled(String componentName) {
         return false;
     }
diff --git a/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java b/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java
index 32a9cf1..25abcb3 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java
@@ -28,6 +28,7 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.CollectionUtils;
 import com.android.internal.util.DataClass;
 
 import java.util.Objects;
@@ -49,7 +50,6 @@
     private boolean mNotLaunched;
     private boolean mHidden; // Is the app restricted by owner / admin
     private int mDistractionFlags;
-    private boolean mSuspended;
     private boolean mInstantApp;
     private boolean mVirtualPreload;
     private int mEnabledState = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
@@ -82,6 +82,8 @@
     @Nullable
     private ArrayMap<ComponentName, Pair<String, Integer>> mComponentLabelIconOverrideMap;
 
+    private long mFirstInstallTime;
+
     public PackageUserStateImpl() {
         super();
     }
@@ -101,7 +103,6 @@
         mNotLaunched = other.mNotLaunched;
         mHidden = other.mHidden;
         mDistractionFlags = other.mDistractionFlags;
-        mSuspended = other.mSuspended;
         mInstantApp = other.mInstantApp;
         mVirtualPreload = other.mVirtualPreload;
         mEnabledState = other.mEnabledState;
@@ -256,6 +257,28 @@
         return mComponentLabelIconOverrideMap.get(componentName);
     }
 
+    @Override
+    public boolean isSuspended() {
+        return !CollectionUtils.isEmpty(mSuspendParams);
+    }
+
+    public PackageUserStateImpl putSuspendParams(@NonNull String suspendingPackage,
+            @NonNull SuspendParams suspendParams) {
+        if (mSuspendParams == null) {
+            mSuspendParams = new ArrayMap<>();
+        }
+        mSuspendParams.put(suspendingPackage, suspendParams);
+        return this;
+    }
+
+    public PackageUserStateImpl removeSuspension(@NonNull String suspendingPackage) {
+        if (mSuspendParams != null) {
+            mSuspendParams.remove(suspendingPackage);
+        }
+        return this;
+    }
+
+
 
 
     // Code below generated by codegen v1.0.23.
@@ -312,11 +335,6 @@
     }
 
     @DataClass.Generated.Member
-    public boolean isSuspended() {
-        return mSuspended;
-    }
-
-    @DataClass.Generated.Member
     public boolean isInstantApp() {
         return mInstantApp;
     }
@@ -385,6 +403,11 @@
     }
 
     @DataClass.Generated.Member
+    public long getFirstInstallTime() {
+        return mFirstInstallTime;
+    }
+
+    @DataClass.Generated.Member
     public @NonNull PackageUserStateImpl setDisabledComponents(@NonNull ArraySet<String> value) {
         mDisabledComponents = value;
         return this;
@@ -433,12 +456,6 @@
     }
 
     @DataClass.Generated.Member
-    public @NonNull PackageUserStateImpl setSuspended( boolean value) {
-        mSuspended = value;
-        return this;
-    }
-
-    @DataClass.Generated.Member
     public @NonNull PackageUserStateImpl setInstantApp( boolean value) {
         mInstantApp = value;
         return this;
@@ -511,6 +528,12 @@
         return this;
     }
 
+    @DataClass.Generated.Member
+    public @NonNull PackageUserStateImpl setFirstInstallTime( long value) {
+        mFirstInstallTime = value;
+        return this;
+    }
+
     @Override
     @DataClass.Generated.Member
     public boolean equals(@Nullable Object o) {
@@ -532,7 +555,6 @@
                 && mNotLaunched == that.mNotLaunched
                 && mHidden == that.mHidden
                 && mDistractionFlags == that.mDistractionFlags
-                && mSuspended == that.mSuspended
                 && mInstantApp == that.mInstantApp
                 && mVirtualPreload == that.mVirtualPreload
                 && mEnabledState == that.mEnabledState
@@ -545,7 +567,8 @@
                 && Objects.equals(mSplashScreenTheme, that.mSplashScreenTheme)
                 && Objects.equals(mSuspendParams, that.mSuspendParams)
                 && Objects.equals(mCachedOverlayPaths, that.mCachedOverlayPaths)
-                && Objects.equals(mComponentLabelIconOverrideMap, that.mComponentLabelIconOverrideMap);
+                && Objects.equals(mComponentLabelIconOverrideMap, that.mComponentLabelIconOverrideMap)
+                && mFirstInstallTime == that.mFirstInstallTime;
     }
 
     @Override
@@ -563,7 +586,6 @@
         _hash = 31 * _hash + Boolean.hashCode(mNotLaunched);
         _hash = 31 * _hash + Boolean.hashCode(mHidden);
         _hash = 31 * _hash + mDistractionFlags;
-        _hash = 31 * _hash + Boolean.hashCode(mSuspended);
         _hash = 31 * _hash + Boolean.hashCode(mInstantApp);
         _hash = 31 * _hash + Boolean.hashCode(mVirtualPreload);
         _hash = 31 * _hash + mEnabledState;
@@ -577,14 +599,15 @@
         _hash = 31 * _hash + Objects.hashCode(mSuspendParams);
         _hash = 31 * _hash + Objects.hashCode(mCachedOverlayPaths);
         _hash = 31 * _hash + Objects.hashCode(mComponentLabelIconOverrideMap);
+        _hash = 31 * _hash + Long.hashCode(mFirstInstallTime);
         return _hash;
     }
 
     @DataClass.Generated(
-            time = 1633983318771L,
+            time = 1640923839971L,
             codegenVersion = "1.0.23",
             sourceFile = "frameworks/base/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java",
-            inputSignatures = "protected @android.annotation.Nullable android.util.ArraySet<java.lang.String> mDisabledComponents\nprotected @android.annotation.Nullable android.util.ArraySet<java.lang.String> mEnabledComponents\nprivate  long mCeDataInode\nprivate  boolean mInstalled\nprivate  boolean mStopped\nprivate  boolean mNotLaunched\nprivate  boolean mHidden\nprivate  int mDistractionFlags\nprivate  boolean mSuspended\nprivate  boolean mInstantApp\nprivate  boolean mVirtualPreload\nprivate  int mEnabledState\nprivate @android.content.pm.PackageManager.InstallReason int mInstallReason\nprivate @android.content.pm.PackageManager.UninstallReason int mUninstallReason\nprivate @android.annotation.Nullable java.lang.String mHarmfulAppWarning\nprivate @android.annotation.Nullable java.lang.String mLastDisableAppCaller\nprotected @android.annotation.Nullable android.content.pm.overlay.OverlayPaths mOverlayPaths\nprotected @android.annotation.Nullable android.util.ArrayMap<java.lang.String,android.content.pm.overlay.OverlayPaths> mSharedLibraryOverlayPaths\nprivate @android.annotation.Nullable java.lang.String mSplashScreenTheme\nprivate @android.annotation.Nullable android.util.ArrayMap<java.lang.String,com.android.server.pm.pkg.SuspendParams> mSuspendParams\nprivate @android.annotation.Nullable android.content.pm.overlay.OverlayPaths mCachedOverlayPaths\nprivate @android.annotation.Nullable android.util.ArrayMap<android.content.ComponentName,android.util.Pair<java.lang.String,java.lang.Integer>> mComponentLabelIconOverrideMap\npublic @android.annotation.Nullable boolean setOverlayPaths(android.content.pm.overlay.OverlayPaths)\npublic  boolean setSharedLibraryOverlayPaths(java.lang.String,android.content.pm.overlay.OverlayPaths)\npublic @android.annotation.Nullable @java.lang.Override android.util.ArraySet<java.lang.String> getDisabledComponentsNoCopy()\npublic @android.annotation.Nullable @java.lang.Override android.util.ArraySet<java.lang.String> getEnabledComponentsNoCopy()\npublic @java.lang.Override boolean isComponentEnabled(java.lang.String)\npublic @java.lang.Override boolean isComponentDisabled(java.lang.String)\npublic @java.lang.Override android.content.pm.overlay.OverlayPaths getAllOverlayPaths()\npublic @com.android.internal.annotations.VisibleForTesting boolean overrideLabelAndIcon(android.content.ComponentName,java.lang.String,java.lang.Integer)\npublic  void resetOverrideComponentLabelIcon()\npublic @android.annotation.Nullable android.util.Pair<java.lang.String,java.lang.Integer> getOverrideLabelIconForComponent(android.content.ComponentName)\nclass PackageUserStateImpl extends java.lang.Object implements [com.android.server.pm.pkg.PackageUserStateInternal]\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=false, genEqualsHashCode=true)")
+            inputSignatures = "protected @android.annotation.Nullable android.util.ArraySet<java.lang.String> mDisabledComponents\nprotected @android.annotation.Nullable android.util.ArraySet<java.lang.String> mEnabledComponents\nprivate  long mCeDataInode\nprivate  boolean mInstalled\nprivate  boolean mStopped\nprivate  boolean mNotLaunched\nprivate  boolean mHidden\nprivate  int mDistractionFlags\nprivate  boolean mInstantApp\nprivate  boolean mVirtualPreload\nprivate  int mEnabledState\nprivate @android.content.pm.PackageManager.InstallReason int mInstallReason\nprivate @android.content.pm.PackageManager.UninstallReason int mUninstallReason\nprivate @android.annotation.Nullable java.lang.String mHarmfulAppWarning\nprivate @android.annotation.Nullable java.lang.String mLastDisableAppCaller\nprotected @android.annotation.Nullable android.content.pm.overlay.OverlayPaths mOverlayPaths\nprotected @android.annotation.Nullable android.util.ArrayMap<java.lang.String,android.content.pm.overlay.OverlayPaths> mSharedLibraryOverlayPaths\nprivate @android.annotation.Nullable java.lang.String mSplashScreenTheme\nprivate @android.annotation.Nullable android.util.ArrayMap<java.lang.String,com.android.server.pm.pkg.SuspendParams> mSuspendParams\nprivate @android.annotation.Nullable android.content.pm.overlay.OverlayPaths mCachedOverlayPaths\nprivate @android.annotation.Nullable android.util.ArrayMap<android.content.ComponentName,android.util.Pair<java.lang.String,java.lang.Integer>> mComponentLabelIconOverrideMap\nprivate  long mFirstInstallTime\npublic @android.annotation.Nullable boolean setOverlayPaths(android.content.pm.overlay.OverlayPaths)\npublic  boolean setSharedLibraryOverlayPaths(java.lang.String,android.content.pm.overlay.OverlayPaths)\npublic @android.annotation.Nullable @java.lang.Override android.util.ArraySet<java.lang.String> getDisabledComponentsNoCopy()\npublic @android.annotation.Nullable @java.lang.Override android.util.ArraySet<java.lang.String> getEnabledComponentsNoCopy()\npublic @java.lang.Override boolean isComponentEnabled(java.lang.String)\npublic @java.lang.Override boolean isComponentDisabled(java.lang.String)\npublic @java.lang.Override android.content.pm.overlay.OverlayPaths getAllOverlayPaths()\npublic @com.android.internal.annotations.VisibleForTesting boolean overrideLabelAndIcon(android.content.ComponentName,java.lang.String,java.lang.Integer)\npublic  void resetOverrideComponentLabelIcon()\npublic @android.annotation.Nullable android.util.Pair<java.lang.String,java.lang.Integer> getOverrideLabelIconForComponent(android.content.ComponentName)\npublic @java.lang.Override boolean isSuspended()\npublic  com.android.server.pm.pkg.PackageUserStateImpl putSuspendParams(java.lang.String,com.android.server.pm.pkg.SuspendParams)\npublic  com.android.server.pm.pkg.PackageUserStateImpl removeSuspension(java.lang.String)\nclass PackageUserStateImpl extends java.lang.Object implements [com.android.server.pm.pkg.PackageUserStateInternal]\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=false, genEqualsHashCode=true)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/services/core/java/com/android/server/pm/pkg/PackageUserStateInternal.java b/services/core/java/com/android/server/pm/pkg/PackageUserStateInternal.java
index 6f33312..bd8b3ab 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageUserStateInternal.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageUserStateInternal.java
@@ -32,6 +32,7 @@
 
     PackageUserStateInternal DEFAULT = new PackageUserStateDefault();
 
+    // TODO: Make non-null with emptyMap()
     @Nullable
     ArrayMap<String, SuspendParams> getSuspendParams();
 
diff --git a/services/core/java/com/android/server/pm/pkg/SuspendParams.java b/services/core/java/com/android/server/pm/pkg/SuspendParams.java
index 71512dc..d24ce96 100644
--- a/services/core/java/com/android/server/pm/pkg/SuspendParams.java
+++ b/services/core/java/com/android/server/pm/pkg/SuspendParams.java
@@ -42,11 +42,15 @@
     private static final String TAG_APP_EXTRAS = "app-extras";
     private static final String TAG_LAUNCHER_EXTRAS = "launcher-extras";
 
-    public SuspendDialogInfo dialogInfo;
-    public PersistableBundle appExtras;
-    public PersistableBundle launcherExtras;
+    private final SuspendDialogInfo dialogInfo;
+    private final PersistableBundle appExtras;
+    private final PersistableBundle launcherExtras;
 
-    private SuspendParams() {
+    private SuspendParams(SuspendDialogInfo dialogInfo, PersistableBundle appExtras,
+            PersistableBundle launcherExtras) {
+        this.dialogInfo = dialogInfo;
+        this.appExtras = appExtras;
+        this.launcherExtras = launcherExtras;
     }
 
     /**
@@ -60,11 +64,7 @@
         if (dialogInfo == null && appExtras == null && launcherExtras == null) {
             return null;
         }
-        final SuspendParams instance = new SuspendParams();
-        instance.dialogInfo = dialogInfo;
-        instance.appExtras = appExtras;
-        instance.launcherExtras = launcherExtras;
-        return instance;
+        return new SuspendParams(dialogInfo, appExtras, launcherExtras);
     }
 
     @Override
@@ -172,4 +172,16 @@
         }
         return getInstanceOrNull(readDialogInfo, readAppExtras, readLauncherExtras);
     }
+
+    public SuspendDialogInfo getDialogInfo() {
+        return dialogInfo;
+    }
+
+    public PersistableBundle getAppExtras() {
+        return appExtras;
+    }
+
+    public PersistableBundle getLauncherExtras() {
+        return launcherExtras;
+    }
 }
diff --git a/services/core/java/com/android/server/pm/pkg/mutate/PackageStateMutator.java b/services/core/java/com/android/server/pm/pkg/mutate/PackageStateMutator.java
new file mode 100644
index 0000000..35d4d9e
--- /dev/null
+++ b/services/core/java/com/android/server/pm/pkg/mutate/PackageStateMutator.java
@@ -0,0 +1,333 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.mutate;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.overlay.OverlayPaths;
+import android.util.ArraySet;
+
+import com.android.server.pm.PackageSetting;
+import com.android.server.pm.pkg.PackageUserStateImpl;
+import com.android.server.pm.pkg.SuspendParams;
+
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.function.Function;
+
+public class PackageStateMutator {
+
+    private static final AtomicLong sStateChangeSequence = new AtomicLong();
+
+    private final StateWriteWrapper mStateWrite = new StateWriteWrapper();
+
+    private final Function<String, PackageSetting> mActiveStateFunction;
+    private final Function<String, PackageSetting> mDisabledStateFunction;
+
+    public PackageStateMutator(@NonNull Function<String, PackageSetting> activeStateFunction,
+            @NonNull Function<String, PackageSetting> disabledStateFunction) {
+        mActiveStateFunction = activeStateFunction;
+        mDisabledStateFunction = disabledStateFunction;
+    }
+
+    public static void onPackageStateChanged() {
+        sStateChangeSequence.incrementAndGet();
+    }
+
+    @NonNull
+    public PackageStateWrite forPackage(@NonNull String packageName) {
+        return mStateWrite.setState(mActiveStateFunction.apply(packageName));
+    }
+
+    @Nullable
+    public PackageStateWrite forPackageNullable(@NonNull String packageName) {
+        final PackageSetting packageState = mActiveStateFunction.apply(packageName);
+        mStateWrite.setState(packageState);
+        if (packageState == null) {
+            return null;
+        }
+
+        return mStateWrite.setState(packageState);
+    }
+
+    @NonNull
+    public PackageStateWrite forDisabledSystemPackage(@NonNull String packageName) {
+        return mStateWrite.setState(mDisabledStateFunction.apply(packageName));
+    }
+
+    @Nullable
+    public PackageStateWrite forDisabledSystemPackageNullable(@NonNull String packageName) {
+        final PackageSetting packageState = mDisabledStateFunction.apply(packageName);
+        if (packageState == null) {
+            return null;
+        }
+
+        return mStateWrite.setState(packageState);
+    }
+
+    @NonNull
+    public InitialState initialState(int changedPackagesSequenceNumber) {
+        return new InitialState(changedPackagesSequenceNumber, sStateChangeSequence.get());
+    }
+
+    /**
+     * @return null if initial state is null or if nothing has changed, otherwise return result
+     * with what changed
+     */
+    @Nullable
+    public Result generateResult(@Nullable InitialState state, int changedPackagesSequenceNumber) {
+        if (state == null) {
+            return Result.SUCCESS;
+        }
+
+        boolean packagesChanged = changedPackagesSequenceNumber != state.mPackageSequence;
+        boolean stateChanged = sStateChangeSequence.get() != state.mStateSequence;
+        if (packagesChanged && stateChanged) {
+            return Result.PACKAGES_AND_STATE_CHANGED;
+        } else if (packagesChanged) {
+            return Result.PACKAGES_CHANGED;
+        } else if (stateChanged) {
+            return Result.STATE_CHANGED;
+        } else {
+            return Result.SUCCESS;
+        }
+    }
+
+    public static class InitialState {
+
+        private final int mPackageSequence;
+        private final long mStateSequence;
+
+        public InitialState(int packageSequence, long stateSequence) {
+            mPackageSequence = packageSequence;
+            mStateSequence = stateSequence;
+        }
+    }
+
+    public static class Result {
+
+        public static final Result SUCCESS = new Result(true, false, false, false);
+        public static final Result PACKAGES_CHANGED = new Result(false, true, false, false);
+        public static final Result STATE_CHANGED = new Result(false, false, true, false);
+        public static final Result PACKAGES_AND_STATE_CHANGED = new Result(false, true, true, false);
+        public static final Result SPECIFIC_PACKAGE_NULL = new Result(false, false, true, true);
+
+        private final boolean mCommitted;
+        private final boolean mPackagesChanged;
+        private final boolean mStateChanged;
+        private final boolean mSpecificPackageNull;
+
+        public Result(boolean committed, boolean packagesChanged, boolean stateChanged,
+                boolean specificPackageNull) {
+            mCommitted = committed;
+            mPackagesChanged = packagesChanged;
+            mStateChanged = stateChanged;
+            mSpecificPackageNull = specificPackageNull;
+        }
+
+        public boolean isCommitted() {
+            return mCommitted;
+        }
+
+        public boolean isPackagesChanged() {
+            return mPackagesChanged;
+        }
+
+        public boolean isStateChanged() {
+            return mStateChanged;
+        }
+
+        public boolean isSpecificPackageNull() {
+            return mSpecificPackageNull;
+        }
+    }
+
+    private static class StateWriteWrapper implements PackageStateWrite {
+
+        private final UserStateWriteWrapper mUserStateWrite = new UserStateWriteWrapper();
+
+        @NonNull
+        private PackageSetting mState;
+
+        public StateWriteWrapper setState(PackageSetting state) {
+            this.mState = state;
+            return this;
+        }
+
+        @NonNull
+        @Override
+        public PackageUserStateWrite userState(int userId) {
+            return mUserStateWrite.setStates(
+                    mState == null ? null : mState.getOrCreateUserState(userId));
+        }
+
+        @Override
+        public PackageStateWrite setLastPackageUsageTime(int reason, long timeInMillis) {
+            if (mState != null) {
+                mState.getTransientState().setLastPackageUsageTimeInMills(reason, timeInMillis);
+            }
+            return this;
+        }
+
+        @Override
+        public PackageStateWrite setHiddenUntilInstalled(boolean value) {
+            if (mState != null) {
+                mState.getTransientState().setHiddenUntilInstalled(value);
+            }
+            return this;
+        }
+
+        @NonNull
+        @Override
+        public PackageStateWrite setRequiredForSystemUser(boolean requiredForSystemUser) {
+            if (mState != null) {
+                if (requiredForSystemUser) {
+                    mState.setPrivateFlags(mState.getPrivateFlags()
+                            | ApplicationInfo.PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER);
+                } else {
+                    mState.setPrivateFlags(mState.getPrivateFlags()
+                            & ~ApplicationInfo.PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER);
+                }
+            }
+            return this;
+        }
+
+        @NonNull
+        @Override
+        public PackageStateWrite setMimeGroup(@NonNull String mimeGroup,
+                @NonNull ArraySet<String> mimeTypes) {
+            if (mState != null) {
+                mState.setMimeGroup(mimeGroup, mimeTypes);
+            }
+            return this;
+        }
+
+        private static class UserStateWriteWrapper implements PackageUserStateWrite {
+
+            @Nullable
+            private PackageUserStateImpl mUserState;
+
+            public UserStateWriteWrapper setStates(@Nullable PackageUserStateImpl userState) {
+                mUserState = userState;
+                return this;
+            }
+
+            @NonNull
+            @Override
+            public PackageUserStateWrite setInstalled(boolean installed) {
+                if (mUserState != null) {
+                    mUserState.setInstalled(installed);
+                }
+                return this;
+            }
+
+            @NonNull
+            @Override
+            public PackageUserStateWrite setUninstallReason(int reason) {
+                if (mUserState != null) {
+                    mUserState.setUninstallReason(reason);
+                }
+                return this;
+            }
+
+            @NonNull
+            @Override
+            public PackageUserStateWrite setDistractionFlags(
+                    @PackageManager.DistractionRestriction int restrictionFlags) {
+                if (mUserState != null) {
+                    mUserState.setDistractionFlags(restrictionFlags);
+                }
+                return this;
+            }
+
+            @NonNull
+            @Override
+            public PackageUserStateWrite putSuspendParams(@NonNull String suspendingPackage,
+                    @Nullable SuspendParams suspendParams) {
+                if (mUserState != null) {
+                    mUserState.putSuspendParams(suspendingPackage, suspendParams);
+                }
+                return this;
+            }
+
+            @NonNull
+            @Override
+            public PackageUserStateWrite removeSuspension(@NonNull String suspendingPackage) {
+                if (mUserState != null) {
+                    mUserState.removeSuspension(suspendingPackage);
+                }
+                return this;
+            }
+
+            @NonNull
+            @Override
+            public PackageUserStateWrite setHidden(boolean hidden) {
+                if (mUserState != null) {
+                    mUserState.setHidden(hidden);
+                }
+                return this;
+            }
+
+            @NonNull
+            @Override
+            public PackageUserStateWrite setStopped(boolean stopped) {
+                if (mUserState != null) {
+                    mUserState.setStopped(stopped);
+                }
+                return this;
+            }
+
+            @NonNull
+            @Override
+            public PackageUserStateWrite setNotLaunched(boolean notLaunched) {
+                if (mUserState != null) {
+                    mUserState.setNotLaunched(notLaunched);
+                }
+                return this;
+            }
+
+            @NonNull
+            @Override
+            public PackageUserStateWrite setOverlayPaths(@NonNull OverlayPaths overlayPaths) {
+                if (mUserState != null) {
+                    mUserState.setOverlayPaths(overlayPaths);
+                }
+                return this;
+            }
+
+            @NonNull
+            @Override
+            public PackageUserStateWrite setOverlayPathsForLibrary(@NonNull String libraryName,
+                    @Nullable OverlayPaths overlayPaths) {
+                if (mUserState != null) {
+                    mUserState.setSharedLibraryOverlayPaths(libraryName, overlayPaths);
+                }
+                return this;
+            }
+
+            @NonNull
+            @Override
+            public PackageUserStateWrite setHarmfulAppWarning(@Nullable String warning) {
+                if (mUserState != null) {
+                    mUserState.setHarmfulAppWarning(warning);
+                }
+                return this;
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/pm/pkg/mutate/PackageStateWrite.java b/services/core/java/com/android/server/pm/pkg/mutate/PackageStateWrite.java
new file mode 100644
index 0000000..585bece
--- /dev/null
+++ b/services/core/java/com/android/server/pm/pkg/mutate/PackageStateWrite.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.pkg.mutate;
+
+import android.annotation.NonNull;
+import android.annotation.UserIdInt;
+import android.content.pm.PackageManager;
+import android.util.ArraySet;
+
+public interface PackageStateWrite {
+
+    @NonNull
+    PackageUserStateWrite userState(@UserIdInt int userId);
+
+    @NonNull
+    PackageStateWrite setLastPackageUsageTime(@PackageManager.NotifyReason int reason,
+            long timeInMillis);
+
+    @NonNull
+    PackageStateWrite setHiddenUntilInstalled(boolean hiddenUntilInstalled);
+
+    @NonNull
+    PackageStateWrite setRequiredForSystemUser(boolean requiredForSystemUser);
+
+    @NonNull
+    PackageStateWrite setMimeGroup(@NonNull String mimeGroup, @NonNull ArraySet<String> mimeTypes);
+}
diff --git a/services/core/java/com/android/server/pm/pkg/mutate/PackageUserStateWrite.java b/services/core/java/com/android/server/pm/pkg/mutate/PackageUserStateWrite.java
new file mode 100644
index 0000000..e23a1b6
--- /dev/null
+++ b/services/core/java/com/android/server/pm/pkg/mutate/PackageUserStateWrite.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 com.android.server.pm.pkg.mutate;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.pm.PackageManager;
+import android.content.pm.overlay.OverlayPaths;
+
+import com.android.server.pm.pkg.SuspendParams;
+
+public interface PackageUserStateWrite {
+
+    @NonNull
+    PackageUserStateWrite setInstalled(boolean installed);
+
+    @NonNull
+    PackageUserStateWrite setUninstallReason(@PackageManager.UninstallReason int reason);
+
+    @NonNull
+    PackageUserStateWrite setDistractionFlags(
+            @PackageManager.DistractionRestriction int restrictionFlags);
+
+    @NonNull
+    PackageUserStateWrite putSuspendParams(@NonNull String suspendingPackage,
+            @Nullable SuspendParams suspendParams);
+
+    @NonNull
+    PackageUserStateWrite removeSuspension(@NonNull String suspendingPackage);
+
+    @NonNull
+    PackageUserStateWrite setHidden(boolean hidden);
+
+    @NonNull
+    PackageUserStateWrite setStopped(boolean stopped);
+
+    @NonNull
+    PackageUserStateWrite setNotLaunched(boolean notLaunched);
+
+    @NonNull
+    PackageUserStateWrite setOverlayPaths(@Nullable OverlayPaths overlayPaths);
+
+    @NonNull
+    PackageUserStateWrite setOverlayPathsForLibrary(@NonNull String libraryName,
+            @Nullable OverlayPaths overlayPaths);
+
+    @NonNull
+    PackageUserStateWrite setHarmfulAppWarning(@Nullable String warning);
+}
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 a3b0e3e..d1603f5 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
@@ -61,6 +61,7 @@
 import com.android.server.pm.Settings;
 import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
+import com.android.server.pm.pkg.PackageStateUtils;
 import com.android.server.pm.pkg.PackageUserState;
 import com.android.server.pm.verify.domain.models.DomainVerificationInternalUserState;
 import com.android.server.pm.verify.domain.models.DomainVerificationPkgState;
@@ -820,10 +821,11 @@
                 PackageStateInternal firstPkgSetting = pkgSettingFunction.apply(first);
                 PackageStateInternal secondPkgSetting = pkgSettingFunction.apply(second);
 
-                long firstInstallTime =
-                        firstPkgSetting == null ? -1L : firstPkgSetting.getFirstInstallTime();
-                long secondInstallTime =
-                        secondPkgSetting == null ? -1L : secondPkgSetting.getFirstInstallTime();
+                long firstInstallTime = firstPkgSetting == null
+                        ? -1L : firstPkgSetting.getUserStateOrDefault(userId).getFirstInstallTime();
+                long secondInstallTime = secondPkgSetting == null
+                        ? -1L
+                        : secondPkgSetting.getUserStateOrDefault(userId).getFirstInstallTime();
 
                 if (firstInstallTime != secondInstallTime) {
                     return (int) (firstInstallTime - secondInstallTime);
@@ -1650,7 +1652,8 @@
                 continue;
             }
 
-            long installTime = pkgSetting.getFirstInstallTime();
+            long installTime = PackageStateUtils.getEarliestFirstInstallTime(
+                    pkgSetting.getUserStates());
             if (installTime > latestInstall) {
                 latestInstall = installTime;
                 targetPackageName = packageName;
@@ -1977,7 +1980,7 @@
             if (pkgSetting == null) {
                 continue;
             }
-            long installTime = pkgSetting.getFirstInstallTime();
+            long installTime = pkgSetting.getUserStateOrDefault(userId).getFirstInstallTime();
             if (installTime > latestInstall) {
                 latestInstall = installTime;
                 filteredPackages.clear();
diff --git a/services/core/java/com/android/server/policy/KeyCombinationManager.java b/services/core/java/com/android/server/policy/KeyCombinationManager.java
index 268de3e..68e078c 100644
--- a/services/core/java/com/android/server/policy/KeyCombinationManager.java
+++ b/services/core/java/com/android/server/policy/KeyCombinationManager.java
@@ -17,11 +17,13 @@
 
 import static android.view.KeyEvent.KEYCODE_POWER;
 
+import android.os.Handler;
 import android.os.SystemClock;
 import android.util.Log;
 import android.util.SparseLongArray;
 import android.view.KeyEvent;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.ToBooleanFunction;
 
 import java.io.PrintWriter;
@@ -35,13 +37,18 @@
     private static final String TAG = "KeyCombinationManager";
 
     // Store the received down time of keycode.
+    @GuardedBy("mLock")
     private final SparseLongArray mDownTimes = new SparseLongArray(2);
     private final ArrayList<TwoKeysCombinationRule> mRules = new ArrayList();
 
     // Selected rules according to current key down.
+    private final Object mLock = new Object();
+    @GuardedBy("mLock")
     private final ArrayList<TwoKeysCombinationRule> mActiveRules = new ArrayList();
     // The rule has been triggered by current keys.
+    @GuardedBy("mLock")
     private TwoKeysCombinationRule mTriggeredRule;
+    private final Handler mHandler = new Handler();
 
     // Keys in a key combination must be pressed within this interval of each other.
     private static final long COMBINE_KEY_DELAY_MILLIS = 150;
@@ -109,6 +116,12 @@
      * Return true if any active rule could be triggered by the key event, otherwise false.
      */
     boolean interceptKey(KeyEvent event, boolean interactive) {
+        synchronized (mLock) {
+            return interceptKeyLocked(event, interactive);
+        }
+    }
+
+    private boolean interceptKeyLocked(KeyEvent event, boolean interactive) {
         final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
         final int keyCode = event.getKeyCode();
         final int count = mActiveRules.size();
@@ -154,7 +167,7 @@
                         return false;
                     }
                     Log.v(TAG, "Performing combination rule : " + rule);
-                    rule.execute();
+                    mHandler.post(rule::execute);
                     mTriggeredRule = rule;
                     return true;
                 });
@@ -169,7 +182,7 @@
             for (int index = count - 1; index >= 0; index--) {
                 final TwoKeysCombinationRule rule = mActiveRules.get(index);
                 if (rule.shouldInterceptKey(keyCode)) {
-                    rule.cancel();
+                    mHandler.post(rule::cancel);
                     mActiveRules.remove(index);
                 }
             }
@@ -181,31 +194,37 @@
      * Return the interceptTimeout to tell InputDispatcher when is ready to deliver to window.
      */
     long getKeyInterceptTimeout(int keyCode) {
-        if (forAllActiveRules((rule) -> rule.shouldInterceptKey(keyCode))) {
-            return mDownTimes.get(keyCode) + COMBINE_KEY_DELAY_MILLIS;
+        synchronized (mLock) {
+            if (forAllActiveRules((rule) -> rule.shouldInterceptKey(keyCode))) {
+                return mDownTimes.get(keyCode) + COMBINE_KEY_DELAY_MILLIS;
+            }
+            return 0;
         }
-        return 0;
     }
 
     /**
      * True if the key event had been handled.
      */
     boolean isKeyConsumed(KeyEvent event) {
-        if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) != 0) {
-            return false;
+        synchronized (mLock) {
+            if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) != 0) {
+                return false;
+            }
+            return mTriggeredRule != null && mTriggeredRule.shouldInterceptKey(event.getKeyCode());
         }
-        return mTriggeredRule != null && mTriggeredRule.shouldInterceptKey(event.getKeyCode());
     }
 
     /**
      * True if power key is the candidate.
      */
     boolean isPowerKeyIntercepted() {
-        if (forAllActiveRules((rule) -> rule.shouldInterceptKey(KEYCODE_POWER))) {
-            // return false if only if power key pressed.
-            return mDownTimes.size() > 1 || mDownTimes.get(KEYCODE_POWER) == 0;
+        synchronized (mLock) {
+            if (forAllActiveRules((rule) -> rule.shouldInterceptKey(KEYCODE_POWER))) {
+                // return false if only if power key pressed.
+                return mDownTimes.size() > 1 || mDownTimes.get(KEYCODE_POWER) == 0;
+            }
+            return false;
         }
-        return false;
     }
 
     /**
diff --git a/services/core/java/com/android/server/policy/LegacyGlobalActions.java b/services/core/java/com/android/server/policy/LegacyGlobalActions.java
index a5969a8..54ece73 100644
--- a/services/core/java/com/android/server/policy/LegacyGlobalActions.java
+++ b/services/core/java/com/android/server/policy/LegacyGlobalActions.java
@@ -138,7 +138,8 @@
         // By default CLOSE_SYSTEM_DIALOGS broadcast is sent only for current user, which is user
         // 10 on devices with headless system user enabled.
         // In order to receive the broadcast, register the broadcast receiver with UserHandle.ALL.
-        context.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);
+        context.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null,
+                Context.RECEIVER_EXPORTED);
 
         mHasTelephony =
                 context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
diff --git a/services/core/java/com/android/server/policy/ModifierShortcutManager.java b/services/core/java/com/android/server/policy/ModifierShortcutManager.java
index e857d32..784e177 100644
--- a/services/core/java/com/android/server/policy/ModifierShortcutManager.java
+++ b/services/core/java/com/android/server/policy/ModifierShortcutManager.java
@@ -112,10 +112,15 @@
      * @return The intent that matches the shortcut, or null if not found.
      */
     private Intent getIntent(KeyCharacterMap kcm, int keyCode, int metaState) {
+        // If a modifier key other than shift is also pressed, skip it.
+        final boolean isShiftOn = KeyEvent.metaStateHasModifiers(metaState, KeyEvent.META_SHIFT_ON);
+        if (!isShiftOn && !KeyEvent.metaStateHasNoModifiers(metaState)) {
+            return null;
+        }
+
         ShortcutInfo shortcut = null;
 
         // If the Shift key is pressed, then search for the shift shortcuts.
-        boolean isShiftOn = (metaState & KeyEvent.META_SHIFT_ON) == KeyEvent.META_SHIFT_ON;
         SparseArray<ShortcutInfo> shortcutMap = isShiftOn ? mShiftShortcuts : mIntentShortcuts;
 
         // First try the exact keycode (with modifiers).
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 298f102..28f65cf 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -363,6 +363,12 @@
     public static final int TOAST_WINDOW_TIMEOUT = 3500 + TOAST_WINDOW_ANIM_BUFFER;
 
     /**
+     * Action for launching assistant in retail mode
+     */
+    private static final String ACTION_VOICE_ASSIST_RETAIL =
+            "android.intent.action.VOICE_ASSIST_RETAIL";
+
+    /**
      * Lock protecting internal state.  Must not call out into window
      * manager with lock held.  (This lock will be acquired in places
      * where the window manager is calling in with its own lock held.)
@@ -1090,29 +1096,35 @@
                 mPowerManager.boostScreenBrightness(eventTime);
                 break;
             case MULTI_PRESS_POWER_LAUNCH_TARGET_ACTIVITY:
-                if (DEBUG_INPUT) {
-                    Slog.d(TAG, "Executing the double press power action.");
-                }
+                launchTargetActivityOnMultiPressPower();
+                break;
+        }
+    }
+
+    private void launchTargetActivityOnMultiPressPower() {
+        if (DEBUG_INPUT) {
+            Slog.d(TAG, "Executing the double press power action.");
+        }
+        if (mPowerDoublePressTargetActivity != null) {
+            Intent intent = new Intent();
+            intent.setComponent(mPowerDoublePressTargetActivity);
+            ResolveInfo resolveInfo = mContext.getPackageManager().resolveActivity(
+                    intent, /* flags= */0);
+            if (resolveInfo != null) {
                 final boolean keyguardActive =
                         mKeyguardDelegate != null && mKeyguardDelegate.isShowing();
+                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                        | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
                 if (!keyguardActive) {
-                    Intent intent = new Intent();
-                    if (mPowerDoublePressTargetActivity != null) {
-                        intent.setComponent(mPowerDoublePressTargetActivity);
-                        ResolveInfo resolveInfo = mContext.getPackageManager().resolveActivity(
-                                intent, /* flags= */0);
-                        if (resolveInfo != null) {
-                            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
-                                    | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
-                            startActivityAsUser(intent, UserHandle.CURRENT_OR_SELF);
-                        } else {
-                            Slog.e(TAG, "Could not resolve activity with : "
-                                    + mPowerDoublePressTargetActivity.flattenToString()
-                                    + " name.");
-                        }
-                    }
+                    startActivityAsUser(intent, UserHandle.CURRENT_OR_SELF);
+                } else {
+                    mKeyguardDelegate.dismissKeyguardToLaunch(intent);
                 }
-                break;
+            } else {
+                Slog.e(TAG, "Could not resolve activity with : "
+                        + mPowerDoublePressTargetActivity.flattenToString()
+                        + " name.");
+            }
         }
     }
 
@@ -1242,6 +1254,12 @@
             return LONG_PRESS_POWER_GLOBAL_ACTIONS;
         }
 
+        // If long press to launch assistant is disabled in settings, do nothing.
+        if (mLongPressOnPowerBehavior == LONG_PRESS_POWER_GO_TO_VOICE_ASSIST
+                && !isLongPressToAssistantEnabled(mContext)) {
+            return LONG_PRESS_POWER_NOTHING;
+        }
+
         return mLongPressOnPowerBehavior;
     }
 
@@ -1273,6 +1291,9 @@
                     intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
                             | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
                     startActivityAsUser(intent, UserHandle.CURRENT_OR_SELF);
+                } else {
+                    // If keyguarded then notify the keyguard.
+                    mKeyguardDelegate.onSystemKeyPressed(KeyEvent.KEYCODE_STEM_PRIMARY);
                 }
                 break;
         }
@@ -2675,6 +2696,7 @@
         final boolean canceled = event.isCanceled();
         final int displayId = event.getDisplayId();
         final long key_consumed = -1;
+        final long key_not_consumed = 0;
 
         if (DEBUG_INPUT) {
             Log.d(TAG, "interceptKeyTi keyCode=" + keyCode + " down=" + down + " repeatCount="
@@ -2864,7 +2886,7 @@
             case KeyEvent.KEYCODE_TAB:
                 if (event.isMetaPressed()) {
                     // Pass through keyboard navigation keys.
-                    return 0;
+                    return key_not_consumed;
                 }
                 // Display task switcher for ALT-TAB.
                 if (down && repeatCount == 0) {
@@ -2895,9 +2917,9 @@
                 return key_consumed;
 
             case KeyEvent.KEYCODE_SPACE:
-                // Handle keyboard layout switching.
-                if ((metaState & (KeyEvent.META_CTRL_MASK | KeyEvent.META_META_MASK)) == 0) {
-                    return 0;
+                // Handle keyboard layout switching. (META + SPACE)
+                if ((metaState & KeyEvent.META_META_MASK) == 0) {
+                    return key_not_consumed;
                 }
                 // Share the same behavior with KEYCODE_LANGUAGE_SWITCH.
             case KeyEvent.KEYCODE_LANGUAGE_SWITCH:
@@ -2971,7 +2993,7 @@
         }
 
         // Let the application handle the key.
-        return 0;
+        return key_not_consumed;
     }
 
     /**
@@ -3037,6 +3059,10 @@
                     + ", policyFlags=" + policyFlags);
         }
 
+        if (interceptUnhandledKey(event)) {
+            return null;
+        }
+
         KeyEvent fallbackEvent = null;
         if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
             final KeyCharacterMap kcm = event.getKeyCharacterMap();
@@ -3091,13 +3117,46 @@
         return fallbackEvent;
     }
 
+    private boolean interceptUnhandledKey(KeyEvent event) {
+        final int keyCode = event.getKeyCode();
+        final int repeatCount = event.getRepeatCount();
+        final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
+        final int metaState = event.getModifiers();
+
+        switch(keyCode) {
+            case KeyEvent.KEYCODE_SPACE:
+                if (down && repeatCount == 0) {
+                    // Handle keyboard layout switching. (CTRL + SPACE)
+                    if (KeyEvent.metaStateHasModifiers(metaState, KeyEvent.META_CTRL_ON)) {
+                        int direction = (metaState & KeyEvent.META_SHIFT_MASK) != 0 ? -1 : 1;
+                        mWindowManagerFuncs.switchKeyboardLayout(event.getDeviceId(), direction);
+                        return true;
+                    }
+                }
+                break;
+            case KeyEvent.KEYCODE_Z:
+                if (down && KeyEvent.metaStateHasModifiers(metaState,
+                        KeyEvent.META_CTRL_ON | KeyEvent.META_ALT_ON)) {
+                    // Intercept the Accessibility keychord (CTRL + ALT + Z) for keyboard users.
+                    if (mAccessibilityShortcutController
+                            .isAccessibilityShortcutAvailable(isKeyguardLocked())) {
+                        mHandler.sendMessage(mHandler.obtainMessage(MSG_ACCESSIBILITY_SHORTCUT));
+                        return true;
+                    }
+                }
+                break;
+        }
+
+        return false;
+    }
+
     private boolean interceptFallback(IBinder focusedToken, KeyEvent fallbackEvent,
             int policyFlags) {
         int actions = interceptKeyBeforeQueueing(fallbackEvent, policyFlags);
         if ((actions & ACTION_PASS_TO_USER) != 0) {
             long delayMillis = interceptKeyBeforeDispatching(
                     focusedToken, fallbackEvent, policyFlags);
-            if (delayMillis == 0) {
+            if (delayMillis == 0 && !interceptUnhandledKey(fallbackEvent)) {
                 return true;
             }
         }
@@ -3218,17 +3277,50 @@
                 .getSystemService(Context.SEARCH_SERVICE)).launchAssist(args);
     }
 
-    /** Launches ACTION_VOICE_ASSIST. Does nothing on keyguard. */
+    /**
+     * Launches ACTION_VOICE_ASSIST_RETAIL if in retail mode, or ACTION_VOICE_ASSIST otherwise
+     * Does nothing on keyguard except for watches. Delegates it to keyguard if present on watch.
+     */
     private void launchVoiceAssist(boolean allowDuringSetup) {
-        final boolean keyguardActive = mKeyguardDelegate == null
-                ? false
-                : mKeyguardDelegate.isShowing();
+        final boolean keyguardActive =
+                mKeyguardDelegate != null && mKeyguardDelegate.isShowing();
         if (!keyguardActive) {
-            Intent intent = new Intent(Intent.ACTION_VOICE_ASSIST);
-            startActivityAsUser(intent, null, UserHandle.CURRENT_OR_SELF,
-                    allowDuringSetup);
+            if (mHasFeatureWatch && isInRetailMode()) {
+                launchRetailVoiceAssist(allowDuringSetup);
+            } else {
+                startVoiceAssistIntent(allowDuringSetup);
+            }
+        } else {
+            mKeyguardDelegate.dismissKeyguardToLaunch(new Intent(Intent.ACTION_VOICE_ASSIST));
         }
+    }
 
+    private void launchRetailVoiceAssist(boolean allowDuringSetup) {
+        Intent retailIntent = new Intent(ACTION_VOICE_ASSIST_RETAIL);
+        ResolveInfo resolveInfo = mContext.getPackageManager().resolveActivity(
+                retailIntent, /* flags= */0);
+        if (resolveInfo != null) {
+            retailIntent.setComponent(
+                    new ComponentName(resolveInfo.activityInfo.packageName,
+                            resolveInfo.activityInfo.name));
+            startActivityAsUser(retailIntent, null, UserHandle.CURRENT_OR_SELF,
+                    allowDuringSetup);
+        } else {
+            Slog.w(TAG, "Couldn't find an app to process " + ACTION_VOICE_ASSIST_RETAIL
+                    + ". Fall back to start " + Intent.ACTION_VOICE_ASSIST);
+            startVoiceAssistIntent(allowDuringSetup);
+        }
+    }
+
+    private void startVoiceAssistIntent(boolean allowDuringSetup) {
+        Intent intent = new Intent(Intent.ACTION_VOICE_ASSIST);
+        startActivityAsUser(intent, null, UserHandle.CURRENT_OR_SELF,
+                allowDuringSetup);
+    }
+
+    private boolean isInRetailMode() {
+        return Settings.Global.getInt(mContext.getContentResolver(),
+                Settings.Global.DEVICE_DEMO_MODE, 0) == 1;
     }
 
     private void startActivityAsUser(Intent intent, UserHandle handle) {
@@ -3935,19 +4027,6 @@
             }
         }
 
-        // Intercept the Accessibility keychord (CTRL + ALT + Z) for keyboard users.
-        if (mAccessibilityShortcutController.isAccessibilityShortcutAvailable(isKeyguardLocked())) {
-            switch (keyCode) {
-                case KeyEvent.KEYCODE_Z: {
-                    if (down && event.isCtrlPressed() && event.isAltPressed()) {
-                        mHandler.sendMessage(mHandler.obtainMessage(MSG_ACCESSIBILITY_SHORTCUT));
-                        result &= ~ACTION_PASS_TO_USER;
-                    }
-                    break;
-                }
-            }
-        }
-
         if (useHapticFeedback) {
             performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY, false,
                     "Virtual Key - Press");
@@ -5824,6 +5903,18 @@
         }
     }
 
+    public static boolean isLongPressToAssistantEnabled(Context context) {
+        ContentResolver resolver = context.getContentResolver();
+        int longPressToAssistant = Settings.System.getIntForUser(resolver,
+                Settings.Global.Wearable.CLOCKWORK_LONG_PRESS_TO_ASSISTANT_ENABLED,
+                /* def= */ 1,
+                UserHandle.USER_CURRENT);
+        if(Log.isLoggable(TAG, Log.DEBUG)) {
+            Log.d(TAG, "longPressToAssistant = " + longPressToAssistant);
+        }
+        return (longPressToAssistant == 1);
+    }
+
     private class HdmiVideoExtconUEventObserver extends ExtconStateObserver<Boolean> {
         private static final String HDMI_EXIST = "HDMI=1";
         private static final String NAME = "hdmi";
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
index 0080ec6..97a57e0 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
@@ -415,6 +415,17 @@
         }
     }
 
+    public void dismissKeyguardToLaunch(Intent intentToLaunch) {
+        if (mKeyguardService != null) {
+            mKeyguardService.dismissKeyguardToLaunch(intentToLaunch);
+        }
+    }
+    public void onSystemKeyPressed(int keycode) {
+        if (mKeyguardService != null) {
+            mKeyguardService.onSystemKeyPressed(keycode);
+        }
+    }
+
     public void dumpDebug(ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
         proto.write(SHOWING, mKeyguardState.showing);
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
index 2029f86..774e261 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
@@ -17,6 +17,7 @@
 package com.android.server.policy.keyguard;
 
 import android.content.Context;
+import android.content.Intent;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.PowerManager;
@@ -254,6 +255,24 @@
         }
     }
 
+    @Override
+    public void dismissKeyguardToLaunch(Intent intentToLaunch) {
+        try {
+            mService.dismissKeyguardToLaunch(intentToLaunch);
+        } catch (RemoteException e) {
+            Slog.w(TAG , "Remote Exception", e);
+        }
+    }
+
+    @Override
+    public void onSystemKeyPressed(int keycode) {
+        try {
+            mService.onSystemKeyPressed(keycode);
+        } catch (RemoteException e) {
+            Slog.w(TAG , "Remote Exception", e);
+        }
+    }
+
     @Override // Binder interface
     public IBinder asBinder() {
         return mService.asBinder();
diff --git a/services/core/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java
index e94575c..b03db66 100644
--- a/services/core/java/com/android/server/power/ShutdownThread.java
+++ b/services/core/java/com/android/server/power/ShutdownThread.java
@@ -213,7 +213,7 @@
         CloseDialogReceiver(Context context) {
             mContext = context;
             IntentFilter filter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
-            context.registerReceiver(this, filter);
+            context.registerReceiver(this, filter, Context.RECEIVER_EXPORTED);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/ObjectPrinter.java b/services/core/java/com/android/server/soundtrigger_middleware/ObjectPrinter.java
index 7f047f8..fba0fb4 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/ObjectPrinter.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/ObjectPrinter.java
@@ -20,8 +20,6 @@
 import android.annotation.Nullable;
 
 import java.lang.reflect.Array;
-import java.lang.reflect.Field;
-import java.lang.reflect.Modifier;
 import java.util.Collection;
 import java.util.Map;
 
@@ -33,67 +31,28 @@
     static public final int kDefaultMaxCollectionLength = 16;
 
     /**
-     * Simple version of {@link #print(Object, boolean, int)} that prints an object, without
-     * recursing into sub-objects.
-     *
-     * @param obj The object to print.
-     * @return A string representing the object.
-     */
-    static String print(@Nullable Object obj) {
-        return print(obj, false, kDefaultMaxCollectionLength);
-    }
-
-    /**
      * Pretty-prints an object.
      *
      * @param obj                 The object to print.
-     * @param deep                Whether to pretty-print sub-objects (if false, just prints them
-     *                            with {@link Object#toString()}).
      * @param maxCollectionLength Whenever encountering collections, maximum number of elements to
      *                            print.
      * @return A string representing the object.
      */
-    static String print(@Nullable Object obj, boolean deep, int maxCollectionLength) {
+    static String print(@Nullable Object obj, int maxCollectionLength) {
         StringBuilder builder = new StringBuilder();
-        print(builder, obj, deep, maxCollectionLength);
+        print(builder, obj, maxCollectionLength);
         return builder.toString();
     }
 
     /**
-     * This version is suitable for use inside a toString() override of an object, e.g.:
-     * <pre><code>
-     *     class MyObject {
-     *         ...
-     *         @Override
-     *         String toString() {
-     *             return ObjectPrinter.printPublicFields(this, ...);
-     *         }
-     *     }
-     * </code></pre>
-     *
-     * @param obj                 The object to print.
-     * @param deep                Whether to pretty-print sub-objects (if false, just prints them
-     *                            with {@link Object#toString()}).
-     * @param maxCollectionLength Whenever encountering collections, maximum number of elements to
-     *                            print.
-     */
-    static String printPublicFields(@Nullable Object obj, boolean deep, int maxCollectionLength) {
-        StringBuilder builder = new StringBuilder();
-        printPublicFields(builder, obj, deep, maxCollectionLength);
-        return builder.toString();
-    }
-
-    /**
-     * A version of {@link #print(Object, boolean, int)} that uses a {@link StringBuilder}.
+     * A version of {@link #print(Object, int)} that uses a {@link StringBuilder}.
      *
      * @param builder             StringBuilder to print into.
      * @param obj                 The object to print.
-     * @param deep                Whether to pretty-print sub-objects (if false, just prints them
-     *                            with {@link Object#toString()}).
      * @param maxCollectionLength Whenever encountering collections, maximum number of elements to
      *                            print.
      */
-    static void print(@NonNull StringBuilder builder, @Nullable Object obj, boolean deep,
+    static void print(@NonNull StringBuilder builder, @Nullable Object obj,
             int maxCollectionLength) {
         try {
             if (obj == null) {
@@ -101,16 +60,16 @@
                 return;
             }
             if (obj instanceof Boolean) {
-                builder.append(obj.toString());
+                builder.append(obj);
                 return;
             }
             if (obj instanceof Number) {
-                builder.append(obj.toString());
+                builder.append(obj);
                 return;
             }
             if (obj instanceof Character) {
                 builder.append('\'');
-                builder.append(obj.toString());
+                builder.append(obj);
                 builder.append('\'');
                 return;
             }
@@ -137,7 +96,7 @@
                         isLong = true;
                         break;
                     }
-                    print(builder, child, deep, maxCollectionLength);
+                    print(builder, child, maxCollectionLength);
                     ++i;
                 }
                 if (isLong) {
@@ -163,9 +122,9 @@
                         isLong = true;
                         break;
                     }
-                    print(builder, child.getKey(), deep, maxCollectionLength);
+                    print(builder, child.getKey(), maxCollectionLength);
                     builder.append(": ");
-                    print(builder, child.getValue(), deep, maxCollectionLength);
+                    print(builder, child.getValue(), maxCollectionLength);
                     ++i;
                 }
                 if (isLong) {
@@ -189,7 +148,7 @@
                         isLong = true;
                         break;
                     }
-                    print(builder, Array.get(obj, i), deep, maxCollectionLength);
+                    print(builder, Array.get(obj, i), maxCollectionLength);
                 }
                 if (isLong) {
                     builder.append("... (+");
@@ -200,48 +159,7 @@
                 return;
             }
 
-            if (!deep) {
-                builder.append(obj.toString());
-                return;
-            }
-            printPublicFields(builder, obj, deep, maxCollectionLength);
-        } catch (Exception e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /**
-     * A version of {@link #printPublicFields(Object, boolean, int)} that uses a {@link
-     * StringBuilder}.
-     *
-     * @param obj                 The object to print.
-     * @param deep                Whether to pretty-print sub-objects (if false, just prints them
-     *                            with {@link Object#toString()}).
-     * @param maxCollectionLength Whenever encountering collections, maximum number of elements to
-     *                            print.
-     */
-    static void printPublicFields(@NonNull StringBuilder builder, @Nullable Object obj,
-            boolean deep,
-            int maxCollectionLength) {
-        try {
-            Class cls = obj.getClass();
-            builder.append("{ ");
-
-            boolean first = true;
-            for (Field fld : cls.getDeclaredFields()) {
-                int mod = fld.getModifiers();
-                if ((mod & Modifier.PUBLIC) != 0 && (mod & Modifier.STATIC) == 0) {
-                    if (first) {
-                        first = false;
-                    } else {
-                        builder.append(", ");
-                    }
-                    builder.append(fld.getName());
-                    builder.append(": ");
-                    print(builder, fld.get(obj), deep, maxCollectionLength);
-                }
-            }
-            builder.append(" }");
+            builder.append(obj);
         } catch (Exception e) {
             throw new RuntimeException(e);
         }
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java
index 559e777..dc4bdaa 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java
@@ -18,14 +18,14 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.media.permission.Identity;
+import android.media.permission.IdentityContext;
 import android.media.soundtrigger.ModelParameterRange;
 import android.media.soundtrigger.PhraseRecognitionEvent;
 import android.media.soundtrigger.PhraseSoundModel;
 import android.media.soundtrigger.RecognitionConfig;
 import android.media.soundtrigger.RecognitionEvent;
 import android.media.soundtrigger.SoundModel;
-import android.media.permission.Identity;
-import android.media.permission.IdentityContext;
 import android.media.soundtrigger_middleware.ISoundTriggerCallback;
 import android.media.soundtrigger_middleware.ISoundTriggerModule;
 import android.media.soundtrigger_middleware.SoundTriggerModuleDescriptor;
@@ -387,7 +387,7 @@
     }
 
     private static void printObject(@NonNull StringBuilder builder, @Nullable Object obj) {
-        ObjectPrinter.print(builder, obj, true, 16);
+        ObjectPrinter.print(builder, obj, 16);
     }
 
     private static String printObject(@Nullable Object obj) {
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java
index 76927e1..f3d151f 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java
@@ -21,9 +21,11 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.app.AppOpsManager;
 import android.content.Context;
 import android.content.PermissionChecker;
+import android.media.permission.Identity;
+import android.media.permission.IdentityContext;
+import android.media.permission.PermissionUtil;
 import android.media.soundtrigger.ModelParameterRange;
 import android.media.soundtrigger.PhraseRecognitionEvent;
 import android.media.soundtrigger.PhraseSoundModel;
@@ -31,9 +33,6 @@
 import android.media.soundtrigger.RecognitionEvent;
 import android.media.soundtrigger.SoundModel;
 import android.media.soundtrigger.Status;
-import android.media.permission.Identity;
-import android.media.permission.IdentityContext;
-import android.media.permission.PermissionUtil;
 import android.media.soundtrigger_middleware.ISoundTriggerCallback;
 import android.media.soundtrigger_middleware.ISoundTriggerMiddlewareService;
 import android.media.soundtrigger_middleware.ISoundTriggerModule;
@@ -144,7 +143,7 @@
         if (status != PermissionChecker.PERMISSION_GRANTED) {
             throw new SecurityException(
                     String.format("Failed to obtain permission %s for identity %s", permission,
-                            ObjectPrinter.print(identity, true, 16)));
+                            ObjectPrinter.print(identity, 16)));
         }
     }
 
@@ -168,7 +167,7 @@
             case PermissionChecker.PERMISSION_HARD_DENIED:
                 throw new SecurityException(
                         String.format("Failed to obtain permission %s for identity %s", permission,
-                                ObjectPrinter.print(identity, true, 16)));
+                                ObjectPrinter.print(identity, 16)));
             default:
                 throw new RuntimeException("Unexpected perimission check result.");
         }
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java
index 4243fc7..09035cd 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java
@@ -18,6 +18,8 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.media.permission.Identity;
+import android.media.permission.IdentityContext;
 import android.media.soundtrigger.ModelParameterRange;
 import android.media.soundtrigger.PhraseRecognitionEvent;
 import android.media.soundtrigger.PhraseSoundModel;
@@ -27,8 +29,6 @@
 import android.media.soundtrigger.RecognitionStatus;
 import android.media.soundtrigger.SoundModel;
 import android.media.soundtrigger.Status;
-import android.media.permission.Identity;
-import android.media.permission.IdentityContext;
 import android.media.soundtrigger_middleware.ISoundTriggerCallback;
 import android.media.soundtrigger_middleware.ISoundTriggerMiddlewareService;
 import android.media.soundtrigger_middleware.ISoundTriggerModule;
@@ -230,7 +230,7 @@
                     final ModuleState module = mModules.get(handle);
                     pw.println("=========================================");
                     pw.printf("Module %d\n%s\n", handle,
-                            ObjectPrinter.print(module.properties, true, 16));
+                            ObjectPrinter.print(module.properties, 16));
                     pw.println("=========================================");
                     for (Session session : module.sessions) {
                         session.dump(pw);
@@ -250,11 +250,11 @@
     /** State of a sound model. */
     static class ModelState {
         ModelState(SoundModel model) {
-            this.description = ObjectPrinter.print(model, true, 16);
+            this.description = ObjectPrinter.print(model, 16);
         }
 
         ModelState(PhraseSoundModel model) {
-            this.description = ObjectPrinter.print(model, true, 16);
+            this.description = ObjectPrinter.print(model, 16);
         }
 
         /** Activity state of a sound model. */
@@ -690,8 +690,8 @@
             if (mState == ModuleStatus.ALIVE) {
                 pw.println("-------------------------------");
                 pw.printf("Session %s, client: %s\n", toString(),
-                        ObjectPrinter.print(mOriginatorIdentity, true, 16));
-                pw.printf("Loaded models (handle, active, description):", toString());
+                        ObjectPrinter.print(mOriginatorIdentity, 16));
+                pw.println("Loaded models (handle, active, description):");
                 pw.println();
                 pw.println("-------------------------------");
                 for (Map.Entry<Integer, ModelState> entry : mLoadedModels.entrySet()) {
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 4eae939..54ec884 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -18,6 +18,9 @@
 
 import static android.app.StatusBarManager.DISABLE2_GLOBAL_ACTIONS;
 import static android.app.StatusBarManager.DISABLE2_NOTIFICATION_SHADE;
+import static android.app.StatusBarManager.NAV_BAR_MODE_OVERRIDE_KIDS;
+import static android.app.StatusBarManager.NAV_BAR_MODE_OVERRIDE_NONE;
+import static android.app.StatusBarManager.NavBarModeOverride;
 import static android.view.Display.DEFAULT_DISPLAY;
 
 import android.Manifest;
@@ -59,6 +62,7 @@
 import android.os.ResultReceiver;
 import android.os.ShellCallback;
 import android.os.UserHandle;
+import android.provider.Settings;
 import android.service.notification.NotificationStats;
 import android.service.quicksettings.TileService;
 import android.text.TextUtils;
@@ -1846,6 +1850,51 @@
         return mContext.getResources().getStringArray(R.array.config_statusBarIcons);
     }
 
+    /**
+     * Sets or removes the navigation bar mode override.
+     *
+     * @param navBarModeOverride the mode of the navigation bar override to be set.
+     */
+    public void setNavBarModeOverride(@NavBarModeOverride int navBarModeOverride) {
+        enforceStatusBar();
+        if (navBarModeOverride != NAV_BAR_MODE_OVERRIDE_NONE
+                && navBarModeOverride != NAV_BAR_MODE_OVERRIDE_KIDS) {
+            throw new UnsupportedOperationException(
+                    "Supplied navBarModeOverride not supported: " + navBarModeOverride);
+        }
+
+        final int userId = mCurrentUserId;
+        final long userIdentity = Binder.clearCallingIdentity();
+        try {
+            Settings.Secure.putIntForUser(mContext.getContentResolver(),
+                    Settings.Secure.NAV_BAR_KIDS_MODE, navBarModeOverride, userId);
+        } finally {
+            Binder.restoreCallingIdentity(userIdentity);
+        }
+    }
+
+    /**
+     * Gets the navigation bar mode override. Returns default value if no override is set.
+     *
+     * @hide
+     */
+    public @NavBarModeOverride int getNavBarModeOverride() {
+        enforceStatusBar();
+
+        int navBarKidsMode = NAV_BAR_MODE_OVERRIDE_NONE;
+        final int userId = mCurrentUserId;
+        final long userIdentity = Binder.clearCallingIdentity();
+        try {
+            navBarKidsMode = Settings.Secure.getIntForUser(mContext.getContentResolver(),
+                    Settings.Secure.NAV_BAR_KIDS_MODE, userId);
+        } catch (Settings.SettingNotFoundException ex) {
+            return navBarKidsMode;
+        } finally {
+            Binder.restoreCallingIdentity(userIdentity);
+        }
+        return navBarKidsMode;
+    }
+
     /** @hide */
     public void passThroughShellCommand(String[] args, FileDescriptor fd) {
         enforceStatusBarOrShell();
diff --git a/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java b/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
index da56824..3093509 100644
--- a/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
+++ b/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
@@ -75,10 +75,12 @@
      */
     public static final String EXTRA_SEQUENCE = "seq";
 
-    private static final int MSG_CHECK = 1;
+    private static final int MSG_CHECK_LOW = 1;
+    private static final int MSG_CHECK_HIGH = 2;
 
     private static final long DEFAULT_LOG_DELTA_BYTES = DataUnit.MEBIBYTES.toBytes(64);
-    private static final long DEFAULT_CHECK_INTERVAL = DateUtils.MINUTE_IN_MILLIS;
+    private static final long LOW_CHECK_INTERVAL = DateUtils.MINUTE_IN_MILLIS;
+    private static final long HIGH_CHECK_INTERVAL = 10 * DateUtils.HOUR_IN_MILLIS;
 
     // com.android.internal.R.string.low_internal_storage_view_text_no_boot
     // hard codes 250MB in the message as the storage space required for the
@@ -165,12 +167,12 @@
     }
 
     /**
-     * Core logic that checks the storage state of every mounted private volume.
-     * Since this can do heavy I/O, callers should invoke indirectly using
-     * {@link #MSG_CHECK}.
+     * Core logic that checks the storage state of every mounted private volume and clears cache
+     * under low storage state. Since this can do heavy I/O, callers should invoke indirectly using
+     * {@link #MSG_CHECK_LOW}.
      */
     @WorkerThread
-    private void check() {
+    private void checkLow() {
         final StorageManager storage = getContext().getSystemService(StorageManager.class);
         final int seq = mSeq.get();
 
@@ -234,9 +236,45 @@
 
         // Loop around to check again in future; we don't remove messages since
         // there might be an immediate request pending.
-        if (!mHandler.hasMessages(MSG_CHECK)) {
-            mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_CHECK),
-                    DEFAULT_CHECK_INTERVAL);
+        if (!mHandler.hasMessages(MSG_CHECK_LOW)) {
+            mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_CHECK_LOW),
+                    LOW_CHECK_INTERVAL);
+        }
+        if (!mHandler.hasMessages(MSG_CHECK_HIGH)) {
+            mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_CHECK_HIGH),
+                    HIGH_CHECK_INTERVAL);
+        }
+    }
+
+    /**
+     * Core logic that checks the storage state of every mounted private volume and clears cache if
+     * free space is under 20% of total space. Since this can do heavy I/O, callers should invoke
+     * indirectly using {@link #MSG_CHECK_HIGH}.
+     */
+    @WorkerThread
+    private void checkHigh() {
+        final StorageManager storage = getContext().getSystemService(StorageManager.class);
+        // Check every mounted private volume to see if they're under the high storage threshold
+        // which is StorageManager.STORAGE_THRESHOLD_PERCENT_HIGH of total space
+        for (VolumeInfo vol : storage.getWritablePrivateVolumes()) {
+            final File file = vol.getPath();
+            if (file.getUsableSpace() < file.getTotalSpace()
+                    * StorageManager.STORAGE_THRESHOLD_PERCENT_HIGH / 100) {
+                final PackageManagerService pms = (PackageManagerService) ServiceManager
+                        .getService("package");
+                try {
+                    pms.freeAllAppCacheAboveQuota(vol.getFsUuid());
+                } catch (IOException e) {
+                    Slog.w(TAG, e);
+                }
+            }
+        }
+
+        // Loop around to check again in future; we don't remove messages since
+        // there might be an immediate request pending
+        if (!mHandler.hasMessages(MSG_CHECK_HIGH)) {
+            mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_CHECK_HIGH),
+                    HIGH_CHECK_INTERVAL);
         }
     }
 
@@ -250,8 +288,11 @@
             @Override
             public void handleMessage(Message msg) {
                 switch (msg.what) {
-                    case MSG_CHECK:
-                        check();
+                    case MSG_CHECK_LOW:
+                        checkLow();
+                        return;
+                    case MSG_CHECK_HIGH:
+                        checkHigh();
                         return;
                 }
             }
@@ -282,16 +323,16 @@
         publishLocalService(DeviceStorageMonitorInternal.class, mLocalService);
 
         // Kick off pass to examine storage state
-        mHandler.removeMessages(MSG_CHECK);
-        mHandler.obtainMessage(MSG_CHECK).sendToTarget();
+        mHandler.removeMessages(MSG_CHECK_LOW);
+        mHandler.obtainMessage(MSG_CHECK_LOW).sendToTarget();
     }
 
     private final DeviceStorageMonitorInternal mLocalService = new DeviceStorageMonitorInternal() {
         @Override
         public void checkMemory() {
             // Kick off pass to examine storage state
-            mHandler.removeMessages(MSG_CHECK);
-            mHandler.obtainMessage(MSG_CHECK).sendToTarget();
+            mHandler.removeMessages(MSG_CHECK_LOW);
+            mHandler.obtainMessage(MSG_CHECK_LOW).sendToTarget();
         }
 
         @Override
@@ -360,8 +401,8 @@
                 mForceLevel = State.LEVEL_LOW;
                 int seq = mSeq.incrementAndGet();
                 if ((opts & OPTION_FORCE_UPDATE) != 0) {
-                    mHandler.removeMessages(MSG_CHECK);
-                    mHandler.obtainMessage(MSG_CHECK).sendToTarget();
+                    mHandler.removeMessages(MSG_CHECK_LOW);
+                    mHandler.obtainMessage(MSG_CHECK_LOW).sendToTarget();
                     pw.println(seq);
                 }
             } break;
@@ -372,8 +413,8 @@
                 mForceLevel = State.LEVEL_NORMAL;
                 int seq = mSeq.incrementAndGet();
                 if ((opts & OPTION_FORCE_UPDATE) != 0) {
-                    mHandler.removeMessages(MSG_CHECK);
-                    mHandler.obtainMessage(MSG_CHECK).sendToTarget();
+                    mHandler.removeMessages(MSG_CHECK_LOW);
+                    mHandler.obtainMessage(MSG_CHECK_LOW).sendToTarget();
                     pw.println(seq);
                 }
             } break;
@@ -384,8 +425,8 @@
                 mForceLevel = State.LEVEL_UNKNOWN;
                 int seq = mSeq.incrementAndGet();
                 if ((opts & OPTION_FORCE_UPDATE) != 0) {
-                    mHandler.removeMessages(MSG_CHECK);
-                    mHandler.obtainMessage(MSG_CHECK).sendToTarget();
+                    mHandler.removeMessages(MSG_CHECK_LOW);
+                    mHandler.obtainMessage(MSG_CHECK_LOW).sendToTarget();
                     pw.println(seq);
                 }
             } break;
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 7e36f89..568e4b8 100755
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -44,6 +44,8 @@
 import android.hardware.hdmi.HdmiControlManager;
 import android.hardware.hdmi.HdmiDeviceInfo;
 import android.media.PlaybackParams;
+import android.media.tv.AdRequest;
+import android.media.tv.AdResponse;
 import android.media.tv.AitInfo;
 import android.media.tv.BroadcastInfoRequest;
 import android.media.tv.BroadcastInfoResponse;
@@ -92,6 +94,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.os.SomeArgs;
+import com.android.internal.util.CollectionUtils;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.FrameworkStatsLog;
 import com.android.internal.util.IndentingPrintWriter;
@@ -1178,6 +1181,91 @@
         }
 
         @Override
+        public List<String> getAvailableExtensionInterfaceNames(String inputId, int userId) {
+            final int callingUid = Binder.getCallingUid();
+            final int callingPid = Binder.getCallingPid();
+            final int resolvedUserId = resolveCallingUserId(callingPid, callingUid,
+                    userId, "getAvailableExtensionInterfaceNames");
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                ITvInputService service = null;
+                synchronized (mLock) {
+                    UserState userState = getOrCreateUserStateLocked(resolvedUserId);
+                    TvInputState inputState = userState.inputMap.get(inputId);
+                    if (inputState != null) {
+                        ServiceState serviceState =
+                                userState.serviceStateMap.get(inputState.info.getComponent());
+                        if (serviceState != null && serviceState.isHardware
+                                && serviceState.service != null) {
+                            service = serviceState.service;
+                        }
+                    }
+                }
+                try {
+                    if (service != null) {
+                        List<String> interfaces = new ArrayList<>();
+                        for (final String name : CollectionUtils.emptyIfNull(
+                                service.getAvailableExtensionInterfaceNames())) {
+                            String permission = service.getExtensionInterfacePermission(name);
+                            if (permission == null
+                                    || mContext.checkPermission(permission, callingPid, callingUid)
+                                    == PackageManager.PERMISSION_GRANTED) {
+                                interfaces.add(name);
+                            }
+                        }
+                        return interfaces;
+                    }
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "error in getAvailableExtensionInterfaceNames "
+                            + "or getExtensionInterfacePermission", e);
+                }
+                return new ArrayList<>();
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public IBinder getExtensionInterface(String inputId, String name, int userId) {
+            final int callingUid = Binder.getCallingUid();
+            final int callingPid = Binder.getCallingPid();
+            final int resolvedUserId = resolveCallingUserId(callingPid, callingUid,
+                    userId, "getExtensionInterface");
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                ITvInputService service = null;
+                synchronized (mLock) {
+                    UserState userState = getOrCreateUserStateLocked(resolvedUserId);
+                    TvInputState inputState = userState.inputMap.get(inputId);
+                    if (inputState != null) {
+                        ServiceState serviceState =
+                                userState.serviceStateMap.get(inputState.info.getComponent());
+                        if (serviceState != null && serviceState.isHardware
+                                && serviceState.service != null) {
+                            service = serviceState.service;
+                        }
+                    }
+                }
+                try {
+                    if (service != null) {
+                        String permission = service.getExtensionInterfacePermission(name);
+                        if (permission == null
+                                || mContext.checkPermission(permission, callingPid, callingUid)
+                                == PackageManager.PERMISSION_GRANTED) {
+                            return service.getExtensionInterface(name);
+                        }
+                    }
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "error in getExtensionInterfacePermission "
+                            + "or getExtensionInterface", e);
+                }
+                return null;
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
         public List<TvContentRatingSystemInfo> getTvContentRatingSystemList(int userId) {
             if (mContext.checkCallingPermission(
                     android.Manifest.permission.READ_CONTENT_RATING_SYSTEMS)
@@ -2382,6 +2470,50 @@
                 }
             } finally {
                 Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public void removeBroadcastInfo(IBinder sessionToken, int requestId, int userId) {
+            final int callingUid = Binder.getCallingUid();
+            final int callingPid = Binder.getCallingPid();
+            final int resolvedUserId = resolveCallingUserId(callingPid, callingUid,
+                    userId, "removeBroadcastInfo");
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    try {
+                        SessionState sessionState = getSessionStateLocked(sessionToken, callingUid,
+                                resolvedUserId);
+                        getSessionLocked(sessionState).removeBroadcastInfo(requestId);
+                    } catch (RemoteException | SessionNotFoundException e) {
+                        Slog.e(TAG, "error in removeBroadcastInfo", e);
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public void requestAd(IBinder sessionToken, AdRequest request, int userId) {
+            final int callingUid = Binder.getCallingUid();
+            final int callingPid = Binder.getCallingPid();
+            final int resolvedUserId = resolveCallingUserId(callingPid, callingUid,
+                    userId, "requestAd");
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    try {
+                        SessionState sessionState = getSessionStateLocked(sessionToken, callingUid,
+                                resolvedUserId);
+                        getSessionLocked(sessionState).requestAd(request);
+                    } catch (RemoteException | SessionNotFoundException e) {
+                        Slog.e(TAG, "error in requestAd", e);
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
             };
         }
 
@@ -3449,6 +3581,23 @@
                 }
             }
         }
+
+        @Override
+        public void onAdResponse (AdResponse response) {
+            synchronized (mLock) {
+                if (DEBUG) {
+                    Slog.d(TAG, "onAdResponse()");
+                }
+                if (mSessionState.session == null || mSessionState.client == null) {
+                    return;
+                }
+                try {
+                    mSessionState.client.onAdResponse(response, mSessionState.seq);
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "error in onAdResponse", e);
+                }
+            }
+        }
     }
 
     @VisibleForTesting
diff --git a/services/core/java/com/android/server/tv/interactive/TvIAppManagerService.java b/services/core/java/com/android/server/tv/interactive/TvIAppManagerService.java
index d70f970..a2bf2fe 100644
--- a/services/core/java/com/android/server/tv/interactive/TvIAppManagerService.java
+++ b/services/core/java/com/android/server/tv/interactive/TvIAppManagerService.java
@@ -29,8 +29,11 @@
 import android.content.pm.ServiceInfo;
 import android.content.pm.UserInfo;
 import android.graphics.Rect;
+import android.media.tv.AdRequest;
+import android.media.tv.AdResponse;
 import android.media.tv.BroadcastInfoRequest;
 import android.media.tv.BroadcastInfoResponse;
+import android.media.tv.TvTrackInfo;
 import android.media.tv.interactive.ITvIAppClient;
 import android.media.tv.interactive.ITvIAppManager;
 import android.media.tv.interactive.ITvIAppManagerCallback;
@@ -157,6 +160,7 @@
             }
             iAppState.mInfo = info;
             iAppState.mUid = getIAppUid(info);
+            iAppState.mComponentName = info.getComponent();
             iAppMap.put(iAppServiceId, iAppState);
             iAppState.mIAppNumber = count;
         }
@@ -652,11 +656,13 @@
                         serviceState = new ServiceState(
                                 componentName, tiasId, resolvedUserId, true, type);
                         userState.mServiceStateMap.put(componentName, serviceState);
+                        updateServiceConnectionLocked(componentName, resolvedUserId);
                     } else if (serviceState.mService != null) {
                         serviceState.mService.prepare(type);
                     } else {
                         serviceState.mPendingPrepare = true;
                         serviceState.mPendingPrepareType = type;
+                        updateServiceConnectionLocked(componentName, resolvedUserId);
                     }
                 }
             } catch (RemoteException e) {
@@ -687,10 +693,12 @@
                                 componentName, tiasId, resolvedUserId);
                         serviceState.addPendingAppLink(appLinkInfo);
                         userState.mServiceStateMap.put(componentName, serviceState);
+                        updateServiceConnectionLocked(componentName, resolvedUserId);
                     } else if (serviceState.mService != null) {
                         serviceState.mService.notifyAppLinkInfo(appLinkInfo);
                     } else {
                         serviceState.addPendingAppLink(appLinkInfo);
+                        updateServiceConnectionLocked(componentName, resolvedUserId);
                     }
                 }
             } catch (RemoteException e) {
@@ -844,13 +852,67 @@
         }
 
         @Override
+        public void notifyTrackSelected(IBinder sessionToken, int type, String trackId,
+                int userId) {
+            if (DEBUG) {
+                Slogf.d(TAG, "notifyTrackSelected(sessionToken=" + sessionToken
+                        + ", type=" + type + ", trackId=" + trackId + ")");
+            }
+            final int callingUid = Binder.getCallingUid();
+            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
+                    userId, "notifyTrackSelected");
+            SessionState sessionState = null;
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    try {
+                        sessionState = getSessionStateLocked(sessionToken, callingUid,
+                                resolvedUserId);
+                        getSessionLocked(sessionState).notifyTrackSelected(type, trackId);
+                    } catch (RemoteException | SessionNotFoundException e) {
+                        Slogf.e(TAG, "error in notifyTrackSelected", e);
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public void notifyTracksChanged(IBinder sessionToken, List<TvTrackInfo> tracks,
+                int userId) {
+            if (DEBUG) {
+                Slogf.d(TAG, "notifyTracksChanged(sessionToken=" + sessionToken
+                        + ", tracks=" + tracks + ")");
+            }
+            final int callingUid = Binder.getCallingUid();
+            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
+                    userId, "notifyTracksChanged");
+            SessionState sessionState = null;
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    try {
+                        sessionState = getSessionStateLocked(sessionToken, callingUid,
+                                resolvedUserId);
+                        getSessionLocked(sessionState).notifyTracksChanged(tracks);
+                    } catch (RemoteException | SessionNotFoundException e) {
+                        Slogf.e(TAG, "error in notifyTracksChanged", e);
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
         public void startIApp(IBinder sessionToken, int userId) {
             if (DEBUG) {
                 Slogf.d(TAG, "BinderService#start(userId=%d)", userId);
             }
             final int callingUid = Binder.getCallingUid();
             final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
-                    userId, "notifyTuned");
+                    userId, "startIApp");
             SessionState sessionState = null;
             final long identity = Binder.clearCallingIdentity();
             try {
@@ -869,6 +931,183 @@
         }
 
         @Override
+        public void stopIApp(IBinder sessionToken, int userId) {
+            if (DEBUG) {
+                Slogf.d(TAG, "BinderService#stop(userId=%d)", userId);
+            }
+            final int callingUid = Binder.getCallingUid();
+            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
+                    userId, "stopIApp");
+            SessionState sessionState = null;
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    try {
+                        sessionState = getSessionStateLocked(sessionToken, callingUid,
+                                resolvedUserId);
+                        getSessionLocked(sessionState).stopIApp();
+                    } catch (RemoteException | SessionNotFoundException e) {
+                        Slogf.e(TAG, "error in stop", e);
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public void createBiInteractiveApp(
+                IBinder sessionToken, Uri biIAppUri, Bundle params, int userId) {
+            if (DEBUG) {
+                Slogf.d(TAG, "createBiInteractiveApp(biIAppUri=%s,params=%s)", biIAppUri, params);
+            }
+            final int callingUid = Binder.getCallingUid();
+            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
+                    userId, "createBiInteractiveApp");
+            SessionState sessionState = null;
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    try {
+                        sessionState = getSessionStateLocked(sessionToken, callingUid,
+                                resolvedUserId);
+                        getSessionLocked(sessionState).createBiInteractiveApp(
+                                biIAppUri, params);
+                    } catch (RemoteException | SessionNotFoundException e) {
+                        Slogf.e(TAG, "error in createBiInteractiveApp", e);
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public void destroyBiInteractiveApp(IBinder sessionToken, String biIAppId, int userId) {
+            if (DEBUG) {
+                Slogf.d(TAG, "destroyBiInteractiveApp(biIAppId=%s)", biIAppId);
+            }
+            final int callingUid = Binder.getCallingUid();
+            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
+                    userId, "destroyBiInteractiveApp");
+            SessionState sessionState = null;
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    try {
+                        sessionState = getSessionStateLocked(sessionToken, callingUid,
+                                resolvedUserId);
+                        getSessionLocked(sessionState).destroyBiInteractiveApp(biIAppId);
+                    } catch (RemoteException | SessionNotFoundException e) {
+                        Slogf.e(TAG, "error in destroyBiInteractiveApp", e);
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public void sendCurrentChannelUri(IBinder sessionToken, Uri channelUri, int userId) {
+            if (DEBUG) {
+                Slogf.d(TAG, "sendCurrentChannelUri(channelUri=%s)", channelUri.toString());
+            }
+            final int callingUid = Binder.getCallingUid();
+            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
+                    userId, "sendCurrentChannelUri");
+            SessionState sessionState = null;
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    try {
+                        sessionState = getSessionStateLocked(sessionToken, callingUid,
+                                resolvedUserId);
+                        getSessionLocked(sessionState).sendCurrentChannelUri(channelUri);
+                    } catch (RemoteException | SessionNotFoundException e) {
+                        Slogf.e(TAG, "error in sendCurrentChannelUri", e);
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public void sendCurrentChannelLcn(IBinder sessionToken, int lcn, int userId) {
+            if (DEBUG) {
+                Slogf.d(TAG, "sendCurrentChannelLcn(lcn=%d)", lcn);
+            }
+            final int callingUid = Binder.getCallingUid();
+            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
+                    userId, "sendCurrentChannelLcn");
+            SessionState sessionState = null;
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    try {
+                        sessionState = getSessionStateLocked(sessionToken, callingUid,
+                                resolvedUserId);
+                        getSessionLocked(sessionState).sendCurrentChannelLcn(lcn);
+                    } catch (RemoteException | SessionNotFoundException e) {
+                        Slogf.e(TAG, "error in sendCurrentChannelLcn", e);
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public void sendStreamVolume(IBinder sessionToken, float volume, int userId) {
+            if (DEBUG) {
+                Slogf.d(TAG, "sendStreamVolume(volume=%f)", volume);
+            }
+            final int callingUid = Binder.getCallingUid();
+            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
+                    userId, "sendStreamVolume");
+            SessionState sessionState = null;
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    try {
+                        sessionState = getSessionStateLocked(sessionToken, callingUid,
+                                resolvedUserId);
+                        getSessionLocked(sessionState).sendStreamVolume(volume);
+                    } catch (RemoteException | SessionNotFoundException e) {
+                        Slogf.e(TAG, "error in sendStreamVolume", e);
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public void sendTrackInfoList(IBinder sessionToken, List<TvTrackInfo> tracks, int userId) {
+            if (DEBUG) {
+                Slogf.d(TAG, "sendTrackInfoList(tracks=%s)", tracks.toString());
+            }
+            final int callingUid = Binder.getCallingUid();
+            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
+                    userId, "sendTrackInfoList");
+            SessionState sessionState = null;
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    try {
+                        sessionState = getSessionStateLocked(sessionToken, callingUid,
+                                resolvedUserId);
+                        getSessionLocked(sessionState).sendTrackInfoList(tracks);
+                    } catch (RemoteException | SessionNotFoundException e) {
+                        Slogf.e(TAG, "error in sendTrackInfoList", e);
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
         public void setSurface(IBinder sessionToken, Surface surface, int userId) {
             final int callingUid = Binder.getCallingUid();
             final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
@@ -941,6 +1180,28 @@
         }
 
         @Override
+        public void notifyAdResponse(IBinder sessionToken, AdResponse response, int userId) {
+            final int callingUid = Binder.getCallingUid();
+            final int callingPid = Binder.getCallingPid();
+            final int resolvedUserId = resolveCallingUserId(callingPid, callingUid, userId,
+                    "notifyAdResponse");
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    try {
+                        SessionState sessionState = getSessionStateLocked(sessionToken, callingUid,
+                                resolvedUserId);
+                        getSessionLocked(sessionState).notifyAdResponse(response);
+                    } catch (RemoteException | SessionNotFoundException e) {
+                        Slogf.e(TAG, "error in notifyAdResponse", e);
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
         public void registerCallback(final ITvIAppManagerCallback callback, int userId) {
             int callingPid = Binder.getCallingPid();
             int callingUid = Binder.getCallingUid();
@@ -1164,7 +1425,8 @@
             serviceState.mReconnecting = false;
         }
 
-        boolean shouldBind = !serviceState.mSessionTokens.isEmpty();
+        boolean shouldBind = (!serviceState.mSessionTokens.isEmpty())
+                || (serviceState.mPendingPrepare) || (!serviceState.mPendingAppLinkInfo.isEmpty());
 
         if (serviceState.mService == null && shouldBind) {
             // This means that the service is not yet connected but its state indicates that we
@@ -1549,6 +1811,23 @@
         }
 
         @Override
+        public void onRemoveBroadcastInfo(int requestId) {
+            synchronized (mLock) {
+                if (DEBUG) {
+                    Slogf.d(TAG, "onRemoveBroadcastInfo (requestId=" + requestId + ")");
+                }
+                if (mSessionState.mSession == null || mSessionState.mClient == null) {
+                    return;
+                }
+                try {
+                    mSessionState.mClient.onRemoveBroadcastInfo(requestId, mSessionState.mSeq);
+                } catch (RemoteException e) {
+                    Slogf.e(TAG, "error in onRemoveBroadcastInfo", e);
+                }
+            }
+        }
+
+        @Override
         public void onCommandRequest(@TvIAppService.IAppServiceCommandType String cmdType,
                 Bundle parameters) {
             synchronized (mLock) {
@@ -1568,6 +1847,108 @@
         }
 
         @Override
+        public void onSetVideoBounds(Rect rect) {
+            synchronized (mLock) {
+                if (DEBUG) {
+                    Slogf.d(TAG, "onSetVideoBounds(rect=" + rect + ")");
+                }
+                if (mSessionState.mSession == null || mSessionState.mClient == null) {
+                    return;
+                }
+                try {
+                    mSessionState.mClient.onSetVideoBounds(rect, mSessionState.mSeq);
+                } catch (RemoteException e) {
+                    Slogf.e(TAG, "error in onSetVideoBounds", e);
+                }
+            }
+        }
+
+        @Override
+        public void onRequestCurrentChannelUri() {
+            synchronized (mLock) {
+                if (DEBUG) {
+                    Slogf.d(TAG, "onRequestCurrentChannelUri");
+                }
+                if (mSessionState.mSession == null || mSessionState.mClient == null) {
+                    return;
+                }
+                try {
+                    mSessionState.mClient.onRequestCurrentChannelUri(mSessionState.mSeq);
+                } catch (RemoteException e) {
+                    Slogf.e(TAG, "error in onRequestCurrentChannelUri", e);
+                }
+            }
+        }
+
+        @Override
+        public void onRequestCurrentChannelLcn() {
+            synchronized (mLock) {
+                if (DEBUG) {
+                    Slogf.d(TAG, "onRequestCurrentChannelLcn");
+                }
+                if (mSessionState.mSession == null || mSessionState.mClient == null) {
+                    return;
+                }
+                try {
+                    mSessionState.mClient.onRequestCurrentChannelLcn(mSessionState.mSeq);
+                } catch (RemoteException e) {
+                    Slogf.e(TAG, "error in onRequestCurrentChannelLcn", e);
+                }
+            }
+        }
+
+        @Override
+        public void onRequestStreamVolume() {
+            synchronized (mLock) {
+                if (DEBUG) {
+                    Slogf.d(TAG, "onRequestStreamVolume");
+                }
+                if (mSessionState.mSession == null || mSessionState.mClient == null) {
+                    return;
+                }
+                try {
+                    mSessionState.mClient.onRequestStreamVolume(mSessionState.mSeq);
+                } catch (RemoteException e) {
+                    Slogf.e(TAG, "error in onRequestStreamVolume", e);
+                }
+            }
+        }
+
+        @Override
+        public void onRequestTrackInfoList() {
+            synchronized (mLock) {
+                if (DEBUG) {
+                    Slogf.d(TAG, "onRequestTrackInfoList");
+                }
+                if (mSessionState.mSession == null || mSessionState.mClient == null) {
+                    return;
+                }
+                try {
+                    mSessionState.mClient.onRequestTrackInfoList(mSessionState.mSeq);
+                } catch (RemoteException e) {
+                    Slogf.e(TAG, "error in onRequestTrackInfoList", e);
+                }
+            }
+        }
+
+        @Override
+        public void onAdRequest(AdRequest request) {
+            synchronized (mLock) {
+                if (DEBUG) {
+                    Slogf.d(TAG, "onAdRequest (id=" + request.getId() + ")");
+                }
+                if (mSessionState.mSession == null || mSessionState.mClient == null) {
+                    return;
+                }
+                try {
+                    mSessionState.mClient.onAdRequest(request, mSessionState.mSeq);
+                } catch (RemoteException e) {
+                    Slogf.e(TAG, "error in onAdRequest", e);
+                }
+            }
+        }
+
+        @Override
         public void onSessionStateChanged(int state) {
             synchronized (mLock) {
                 if (DEBUG) {
@@ -1584,6 +1965,25 @@
             }
         }
 
+        @Override
+        public void onBiInteractiveAppCreated(Uri biIAppUri, String biIAppId) {
+            synchronized (mLock) {
+                if (DEBUG) {
+                    Slogf.d(TAG, "onBiInteractiveAppCreated (biIAppUri=" + biIAppUri
+                            + ", biIAppId=" + biIAppId + ")");
+                }
+                if (mSessionState.mSession == null || mSessionState.mClient == null) {
+                    return;
+                }
+                try {
+                    mSessionState.mClient.onBiInteractiveAppCreated(
+                            biIAppUri, biIAppId, mSessionState.mSeq);
+                } catch (RemoteException e) {
+                    Slogf.e(TAG, "error in onBiInteractiveAppCreated", e);
+                }
+            }
+        }
+
         @GuardedBy("mLock")
         private boolean addSessionTokenToClientStateLocked(ITvIAppSession session) {
             try {
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 e508260..63f4c68 100644
--- a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
+++ b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
@@ -21,6 +21,7 @@
 import android.app.ActivityManager;
 import android.app.ActivityManager.RunningAppProcessInfo;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.media.IResourceManagerService;
 import android.media.tv.TvInputManager;
 import android.media.tv.tunerresourcemanager.CasSessionRequest;
@@ -543,6 +544,12 @@
         protected void dump(FileDescriptor fd, final PrintWriter writer, String[] args) {
             final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
 
+            if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+                    != PackageManager.PERMISSION_GRANTED) {
+                pw.println("Permission Denial: can't dump!");
+                return;
+            }
+
             synchronized (mLock) {
                 if (mClientProfiles != null) {
                     pw.println("ClientProfiles:");
diff --git a/services/core/java/com/android/server/vr/Vr2dDisplay.java b/services/core/java/com/android/server/vr/Vr2dDisplay.java
index 39d7a15..7697490 100644
--- a/services/core/java/com/android/server/vr/Vr2dDisplay.java
+++ b/services/core/java/com/android/server/vr/Vr2dDisplay.java
@@ -177,7 +177,7 @@
                         }
                     }
                 }
-            }, intentFilter);
+            }, intentFilter, Context.RECEIVER_NOT_EXPORTED);
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index 2f9c138..4b33f0e 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -60,6 +60,11 @@
 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.internal.util.FrameworkStatsLog.CAMERA_COMPAT_CONTROL_EVENT_REPORTED__EVENT__APPEARED_APPLY_TREATMENT;
+import static com.android.internal.util.FrameworkStatsLog.CAMERA_COMPAT_CONTROL_EVENT_REPORTED__EVENT__APPEARED_REVERT_TREATMENT;
+import static com.android.internal.util.FrameworkStatsLog.CAMERA_COMPAT_CONTROL_EVENT_REPORTED__EVENT__CLICKED_APPLY_TREATMENT;
+import static com.android.internal.util.FrameworkStatsLog.CAMERA_COMPAT_CONTROL_EVENT_REPORTED__EVENT__CLICKED_DISMISS;
+import static com.android.internal.util.FrameworkStatsLog.CAMERA_COMPAT_CONTROL_EVENT_REPORTED__EVENT__CLICKED_REVERT_TREATMENT;
 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;
@@ -72,6 +77,8 @@
 import android.annotation.Nullable;
 import android.app.ActivityOptions;
 import android.app.ActivityOptions.SourceInfo;
+import android.app.TaskInfo;
+import android.app.TaskInfo.CameraCompatControlState;
 import android.app.WaitResult;
 import android.app.WindowConfiguration.WindowingMode;
 import android.content.ComponentName;
@@ -1374,6 +1381,71 @@
         }
     }
 
+    /**
+     * Logs the Camera Compat Control appeared event that corresponds to the given {@code state}
+     * with the given {@code packageUid}.
+     */
+    void logCameraCompatControlAppearedEventReported(@CameraCompatControlState int state,
+            int packageUid) {
+        switch (state) {
+            case TaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED:
+                logCameraCompatControlEventReported(
+                        CAMERA_COMPAT_CONTROL_EVENT_REPORTED__EVENT__APPEARED_APPLY_TREATMENT,
+                        packageUid);
+                break;
+            case TaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED:
+                logCameraCompatControlEventReported(
+                        CAMERA_COMPAT_CONTROL_EVENT_REPORTED__EVENT__APPEARED_REVERT_TREATMENT,
+                        packageUid);
+                break;
+            case TaskInfo.CAMERA_COMPAT_CONTROL_HIDDEN:
+                // Nothing to log.
+                break;
+            default:
+                Slog.w(TAG, "Unexpected state in logCameraCompatControlAppearedEventReported: "
+                        + state);
+                break;
+        }
+    }
+
+    /**
+     * Logs the Camera Compat Control clicked event that corresponds to the given {@code state}
+     * with the given {@code packageUid}.
+     */
+    void logCameraCompatControlClickedEventReported(@CameraCompatControlState int state,
+            int packageUid) {
+        switch (state) {
+            case TaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED:
+                logCameraCompatControlEventReported(
+                        CAMERA_COMPAT_CONTROL_EVENT_REPORTED__EVENT__CLICKED_APPLY_TREATMENT,
+                        packageUid);
+                break;
+            case TaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED:
+                logCameraCompatControlEventReported(
+                        CAMERA_COMPAT_CONTROL_EVENT_REPORTED__EVENT__CLICKED_REVERT_TREATMENT,
+                        packageUid);
+                break;
+            case TaskInfo.CAMERA_COMPAT_CONTROL_DISMISSED:
+                logCameraCompatControlEventReported(
+                        CAMERA_COMPAT_CONTROL_EVENT_REPORTED__EVENT__CLICKED_DISMISS,
+                        packageUid);
+                break;
+            default:
+                Slog.w(TAG, "Unexpected state in logCameraCompatControlAppearedEventReported: "
+                        + state);
+                break;
+        }
+    }
+
+    private void logCameraCompatControlEventReported(int event, int packageUid) {
+        FrameworkStatsLog.write(FrameworkStatsLog.CAMERA_COMPAT_CONTROL_EVENT_REPORTED, packageUid,
+                event);
+        if (DEBUG_METRICS) {
+            Slog.i(TAG, String.format("CAMERA_COMPAT_CONTROL_EVENT_REPORTED(%s, %s)", packageUid,
+                    event));
+        }
+    }
+
     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 cde5273..0b0b704 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -1615,6 +1615,8 @@
         if (!changed) {
             return;
         }
+        mTaskSupervisor.getActivityMetricsLogger().logCameraCompatControlAppearedEventReported(
+                newCameraCompatControlState, info.applicationInfo.uid);
         if (newCameraCompatControlState == TaskInfo.CAMERA_COMPAT_CONTROL_HIDDEN) {
             mCameraCompatControlClickedByUser = false;
             mCompatCameraControlCallback = null;
@@ -1637,6 +1639,8 @@
         if (!changed) {
             return;
         }
+        mTaskSupervisor.getActivityMetricsLogger().logCameraCompatControlClickedEventReported(
+                state, info.applicationInfo.uid);
         if (state == TaskInfo.CAMERA_COMPAT_CONTROL_DISMISSED) {
             mCompatCameraControlCallback = null;
             return;
@@ -4003,6 +4007,13 @@
     private boolean transferStartingWindow(@NonNull ActivityRecord fromActivity) {
         final WindowState tStartingWindow = fromActivity.mStartingWindow;
         if (tStartingWindow != null && fromActivity.mStartingSurface != null) {
+            if (tStartingWindow.getParent() == null) {
+                // The window has been detached from the parent, so the window cannot be transfer
+                // to another activity because it may be in the remove process.
+                // Don't need to remove the starting window at this point because that will happen
+                // at #postWindowRemoveCleanupLocked
+                return false;
+            }
             // In this case, the starting icon has already been displayed, so start
             // letting windows get shown immediately without any more transitions.
             if (fromActivity.mVisible) {
@@ -4121,8 +4132,7 @@
         final boolean containsShowWhenLocked = containsShowWhenLockedWindow();
         if (containsDismissKeyguard != mLastContainsDismissKeyguardWindow
                 || containsShowWhenLocked != mLastContainsShowWhenLockedWindow) {
-            mWmService.notifyKeyguardFlagsChanged(null /* callback */,
-                    getDisplayContent().getDisplayId());
+            mDisplayContent.notifyKeyguardFlagsChanged();
         }
         mLastContainsDismissKeyguardWindow = containsDismissKeyguard;
         mLastContainsShowWhenLockedWindow = containsShowWhenLocked;
@@ -6327,7 +6337,6 @@
                 }
             } else if (w.isDrawn()) {
                 // The starting window for this container is drawn.
-                mTaskSupervisor.getActivityMetricsLogger().notifyStartingWindowDrawn(this);
                 startingDisplayed = true;
             }
         }
@@ -6896,8 +6905,7 @@
                 getSyncTransaction().hide(mSurfaceControl);
             }
             if (show) {
-                mActivityRecordInputSink.applyChangesToSurfaceIfChanged(
-                        getSyncTransaction(), mSurfaceControl);
+                mActivityRecordInputSink.applyChangesToSurfaceIfChanged(getSyncTransaction());
             }
         }
         if (mThumbnail != null) {
diff --git a/services/core/java/com/android/server/wm/ActivityRecordInputSink.java b/services/core/java/com/android/server/wm/ActivityRecordInputSink.java
index b183281..9353f6d 100644
--- a/services/core/java/com/android/server/wm/ActivityRecordInputSink.java
+++ b/services/core/java/com/android/server/wm/ActivityRecordInputSink.java
@@ -55,12 +55,12 @@
 
     private final ActivityRecord mActivityRecord;
     private final boolean mIsCompatEnabled;
+    private final String mName;
 
     // Hold on to InputEventReceiver to prevent it from getting GCd.
     private InputEventReceiver mInputEventReceiver;
     private InputWindowHandleWrapper mInputWindowHandleWrapper;
-    private final String mName = Integer.toHexString(System.identityHashCode(this))
-            + " ActivityRecordInputSink";
+    private SurfaceControl mSurfaceControl;
     private int mRapidTouchCount = 0;
     private IBinder mToken;
     private boolean mDisabled = false;
@@ -69,14 +69,29 @@
         mActivityRecord = activityRecord;
         mIsCompatEnabled = CompatChanges.isChangeEnabled(ENABLE_TOUCH_OPAQUE_ACTIVITIES,
                 mActivityRecord.getUid());
+        mName = Integer.toHexString(System.identityHashCode(this)) + " ActivityRecordInputSink "
+                + mActivityRecord.mActivityComponent.getShortClassName();
     }
 
-    public void applyChangesToSurfaceIfChanged(
-            SurfaceControl.Transaction transaction, SurfaceControl surfaceControl) {
+    public void applyChangesToSurfaceIfChanged(SurfaceControl.Transaction transaction) {
         InputWindowHandleWrapper inputWindowHandleWrapper = getInputWindowHandleWrapper();
-        if (inputWindowHandleWrapper.isChanged()) {
-            inputWindowHandleWrapper.applyChangesToSurface(transaction, surfaceControl);
+        if (mSurfaceControl == null) {
+            mSurfaceControl = createSurface(transaction);
         }
+        if (inputWindowHandleWrapper.isChanged()) {
+            inputWindowHandleWrapper.applyChangesToSurface(transaction, mSurfaceControl);
+        }
+    }
+
+    private SurfaceControl createSurface(SurfaceControl.Transaction t) {
+        SurfaceControl surfaceControl = mActivityRecord.makeChildSurface(null)
+                .setName(mName)
+                .setHidden(false)
+                .setCallsite("ActivityRecordInputSink.createSurface")
+                .build();
+        // Put layer below all siblings (and the parent surface too)
+        t.setLayer(surfaceControl, Integer.MIN_VALUE);
+        return surfaceControl;
     }
 
     private InputWindowHandleWrapper getInputWindowHandleWrapper() {
@@ -91,11 +106,6 @@
                 ANIMATION_TYPE_APP_TRANSITION)) {
             // TODO(b/208662670): Investigate if we can have feature active during animations.
             mInputWindowHandleWrapper.setToken(null);
-        } else if (mActivityRecord.mStartingData != null) {
-            // TODO(b/208659130): Remove this special case
-            // Don't block touches during splash screen. This is done to not show toasts for
-            // touches passing through splash screens. b/171772640
-            mInputWindowHandleWrapper.setToken(null);
         } else {
             mInputWindowHandleWrapper.setToken(mToken);
         }
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index 7fa9861..a9142ef 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -243,21 +243,6 @@
             int startFlags, @Nullable Bundle options, int userId);
 
     /**
-     * Called when Keyguard flags might have changed.
-     *
-     * @param callback Callback to run after activity visibilities have been reevaluated. This can
-     *                 be used from window manager so that when the callback is called, it's
-     *                 guaranteed that all apps have their visibility updated accordingly.
-     * @param displayId The id of the display where the keyguard flags changed.
-     */
-    public abstract void notifyKeyguardFlagsChanged(@Nullable Runnable callback, int displayId);
-
-    /**
-     * Called when the trusted state of Keyguard has changed.
-     */
-    public abstract void notifyKeyguardTrustedChanged();
-
-    /**
      * Called after virtual display Id is updated by
      * {@link com.android.server.vr.Vr2dDisplay} with a specific
      * {@param vr2dDisplayId}.
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 173545c..15ebe28 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -63,7 +63,6 @@
 import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.INVALID_DISPLAY;
-import static android.view.WindowManager.TRANSIT_NONE;
 import static android.view.WindowManager.TRANSIT_WAKE;
 
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
@@ -5415,42 +5414,6 @@
                     false /*validateIncomingUser*/);
         }
 
-        @Override
-        public void notifyKeyguardFlagsChanged(@Nullable Runnable callback, int displayId) {
-            synchronized (mGlobalLock) {
-
-                // We might change the visibilities here, so prepare an empty app transition which
-                // might be overridden later if we actually change visibilities.
-                final DisplayContent dc = mRootWindowContainer.getDisplayContent(displayId);
-                if (dc == null) {
-                    return;
-                }
-                final boolean wasTransitionSet = dc.mAppTransition.isTransitionSet();
-                if (!wasTransitionSet) {
-                    dc.prepareAppTransition(TRANSIT_NONE);
-                }
-                mRootWindowContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
-
-                // If there was a transition set already we don't want to interfere with it as we
-                // might be starting it too early.
-                if (!wasTransitionSet) {
-                    dc.executeAppTransition();
-                }
-            }
-            if (callback != null) {
-                callback.run();
-            }
-        }
-
-        @Override
-        public void notifyKeyguardTrustedChanged() {
-            synchronized (mGlobalLock) {
-                if (mKeyguardController.isKeyguardShowing(DEFAULT_DISPLAY)) {
-                    mRootWindowContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
-                }
-            }
-        }
-
         /**
          * Called after virtual display Id is updated by
          * {@link com.android.server.vr.Vr2dDisplay} with a specific
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index 51c8daf..3cecce2 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -641,22 +641,35 @@
             intent.setComponent(new ComponentName(
                     aInfo.applicationInfo.packageName, aInfo.name));
 
-            // Don't debug things in the system process
-            if (!aInfo.processName.equals("system")) {
-                if ((startFlags & (START_FLAG_DEBUG | START_FLAG_NATIVE_DEBUGGING
-                        | START_FLAG_TRACK_ALLOCATION)) != 0 || profilerInfo != null) {
-
+            final boolean requestDebug = (startFlags & (START_FLAG_DEBUG
+                    | START_FLAG_NATIVE_DEBUGGING | START_FLAG_TRACK_ALLOCATION)) != 0;
+            final boolean requestProfile = profilerInfo != null;
+            if (requestDebug || requestProfile) {
+                final boolean debuggable = (Build.IS_DEBUGGABLE
+                        || (aInfo.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0)
+                        && !aInfo.processName.equals("system");
+                if ((requestDebug && !debuggable) || (requestProfile
+                        && (!debuggable && !aInfo.applicationInfo.isProfileableByShell()))) {
+                    Slog.w(TAG, "Ignore debugging for non-debuggable app: " + aInfo.packageName);
+                } else {
                      // Mimic an AMS synchronous call by passing a message to AMS and wait for AMS
                      // to notify us that the task has completed.
                      // TODO(b/80414790) look into further untangling for the situation where the
                      // caller is on the same thread as the handler we are posting to.
                     synchronized (mService.mGlobalLock) {
                         // Post message to AMS.
-                        final Message msg = PooledLambda.obtainMessage(
-                                ActivityManagerInternal::setDebugFlagsForStartingActivity,
-                                mService.mAmInternal, aInfo, startFlags, profilerInfo,
-                                mService.mGlobalLock);
-                        mService.mH.sendMessage(msg);
+                        mService.mH.post(() -> {
+                            try {
+                                mService.mAmInternal.setDebugFlagsForStartingActivity(aInfo,
+                                        startFlags, profilerInfo, mService.mGlobalLock);
+                            } catch (Throwable e) {
+                                // Simply ignore it because the debugging doesn't take effect.
+                                Slog.w(TAG, e);
+                                synchronized (mService.mGlobalLockWithoutBoost) {
+                                    mService.mGlobalLockWithoutBoost.notifyAll();
+                                }
+                            }
+                        });
                         try {
                             mService.mGlobalLock.wait();
                         } catch (InterruptedException ignore) {
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index 721907c..3d37278 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -799,6 +799,22 @@
     }
 
     /**
+     * Returns {@code true} if a given {@link WindowContainer} is an embedded Task.
+     *
+     * Note that this is a short term workaround to support Android Auto until it migrate to
+     * ShellTransition. This should only be used by {@link #getAnimationTargets}.
+     *
+     * TODO(b/213312721): Remove this predicate and its callers once ShellTransition is enabled.
+     */
+    private static boolean isEmbeddedTask(WindowContainer wc) {
+        // We use Task#mRemoveWithTaskOrganizer to identify an embedded Task, but this is a hack and
+        // it is not guaranteed to work this logic in the future version.
+        return !WindowManagerService.sEnableShellTransitions
+                && wc instanceof Task
+                && ((Task) wc).mRemoveWithTaskOrganizer;
+    }
+
+    /**
      * Find WindowContainers to be animated from a set of opening and closing apps. We will promote
      * animation targets to higher level in the window hierarchy if possible.
      *
@@ -844,7 +860,13 @@
             siblings.add(current);
             boolean canPromote = true;
 
-            if (parent == null || !parent.canCreateRemoteAnimationTarget()
+            if (isEmbeddedTask(current)) {
+                // Don't animate an embedded Task in app transition. This is a short term workaround
+                // to prevent conflict of surface hierarchy changes between legacy app transition
+                // and TaskView (b/205189147).
+                // TODO(b/213312721): Remove this once ShellTransition is enabled.
+                continue;
+            } else 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
@@ -887,7 +909,13 @@
                 for (int j = 0; j < parent.getChildCount(); ++j) {
                     final WindowContainer sibling = parent.getChildAt(j);
                     if (candidates.remove(sibling)) {
-                        siblings.add(sibling);
+                        if (!isEmbeddedTask(sibling)) {
+                            // Don't animate an embedded Task in app transition. This is a short
+                            // term workaround to prevent conflict of surface hierarchy changes
+                            // between legacy app transition and TaskView (b/205189147).
+                            // TODO(b/213312721): Remove this once ShellTransition is enabled.
+                            siblings.add(sibling);
+                        }
                     } else if (sibling != current && sibling.isVisible()) {
                         canPromote = false;
                     }
diff --git a/services/core/java/com/android/server/wm/BLASTSyncEngine.java b/services/core/java/com/android/server/wm/BLASTSyncEngine.java
index 2a8ac39e..bb4519c 100644
--- a/services/core/java/com/android/server/wm/BLASTSyncEngine.java
+++ b/services/core/java/com/android/server/wm/BLASTSyncEngine.java
@@ -16,9 +16,12 @@
 
 package com.android.server.wm;
 
+import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
+
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_SYNC_ENGINE;
 
 import android.annotation.NonNull;
+import android.os.Trace;
 import android.util.ArraySet;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -71,8 +74,9 @@
         boolean mReady = false;
         final ArraySet<WindowContainer> mRootMembers = new ArraySet<>();
         private SurfaceControl.Transaction mOrphanTransaction = null;
+        private String mTraceName;
 
-        private SyncGroup(TransactionReadyListener listener, int id) {
+        private SyncGroup(TransactionReadyListener listener, int id, String name) {
             mSyncId = id;
             mListener = listener;
             mOnTimeout = () -> {
@@ -81,6 +85,10 @@
                     onTimeout();
                 }
             };
+            if (Trace.isTagEnabled(TRACE_TAG_WINDOW_MANAGER)) {
+                mTraceName = name + "SyncGroupReady";
+                Trace.asyncTraceBegin(TRACE_TAG_WINDOW_MANAGER, mTraceName, id);
+            }
         }
 
         /**
@@ -113,6 +121,9 @@
         }
 
         private void finishNow() {
+            if (mTraceName != null) {
+                Trace.asyncTraceEnd(TRACE_TAG_WINDOW_MANAGER, mTraceName, mSyncId);
+            }
             ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncGroup %d: Finished!", mSyncId);
             SurfaceControl.Transaction merged = mWm.mTransactionFactory.get();
             if (mOrphanTransaction != null) {
@@ -121,7 +132,9 @@
             for (WindowContainer wc : mRootMembers) {
                 wc.finishSync(merged, false /* cancel */);
             }
+            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "onTransactionReady");
             mListener.onTransactionReady(mSyncId, merged);
+            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
             mActiveSyncs.remove(mSyncId);
             mWm.mH.removeCallbacks(mOnTimeout);
         }
@@ -168,12 +181,12 @@
     }
 
     int startSyncSet(TransactionReadyListener listener) {
-        return startSyncSet(listener, WindowState.BLAST_TIMEOUT_DURATION);
+        return startSyncSet(listener, WindowState.BLAST_TIMEOUT_DURATION, "");
     }
 
-    int startSyncSet(TransactionReadyListener listener, long timeoutMs) {
+    int startSyncSet(TransactionReadyListener listener, long timeoutMs, String name) {
         final int id = mNextSyncId++;
-        final SyncGroup s = new SyncGroup(listener, id);
+        final SyncGroup s = new SyncGroup(listener, id, name);
         mActiveSyncs.put(id, s);
         ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncGroup %d: Started for listener: %s", id, listener);
         scheduleTimeout(s, timeoutMs);
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index e80a9b9..c740f7b 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -80,6 +80,7 @@
 import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
 import static android.view.WindowManager.TRANSIT_CHANGE;
+import static android.view.WindowManager.TRANSIT_NONE;
 import static android.view.WindowManager.TRANSIT_OPEN;
 import static android.view.WindowManager.TRANSIT_TO_FRONT;
 import static android.window.DisplayAreaOrganizer.FEATURE_IME;
@@ -1466,7 +1467,7 @@
     @Override
     boolean onDescendantOrientationChanged(WindowContainer requestingContainer) {
         final Configuration config = updateOrientation(
-                getRequestedOverrideConfiguration(), requestingContainer, false /* forceUpdate */);
+                requestingContainer, false /* forceUpdate */);
         // If display rotation class tells us that it doesn't consider app requested orientation,
         // this display won't rotate just because of an app changes its requested orientation. Thus
         // it indicates that this display chooses not to handle this request.
@@ -1515,14 +1516,10 @@
      * DisplayContent)} to tell the window manager it can unfreeze the screen. This will typically
      * be done by calling {@link #sendNewConfiguration}.
      *
-     * @param currentConfig The current requested override configuration (it is usually set from
-     *                      the last {@link #sendNewConfiguration}) of the display. It is used to
-     *                      check if the configuration container has the latest state.
      * @param freezeDisplayWindow Freeze the app window if the orientation is changed.
      * @param forceUpdate See {@link DisplayRotation#updateRotationUnchecked(boolean)}
      */
-    Configuration updateOrientation(Configuration currentConfig,
-            WindowContainer freezeDisplayWindow, boolean forceUpdate) {
+    Configuration updateOrientation(WindowContainer<?> freezeDisplayWindow, boolean forceUpdate) {
         if (!mDisplayReady) {
             return null;
         }
@@ -1539,15 +1536,15 @@
             }
             config = new Configuration();
             computeScreenConfiguration(config);
-        } else if (currentConfig != null
+        } else if (!(mTransitionController.isCollecting(this)
                 // If waiting for a remote rotation, don't prematurely update configuration.
-                && !(mDisplayRotation.isWaitingForRemoteRotation()
-                        || mTransitionController.isCollecting(this))) {
+                || mDisplayRotation.isWaitingForRemoteRotation())) {
             // No obvious action we need to take, but if our current state mismatches the
             // activity manager's, update it, disregarding font scale, which should remain set
             // to the value of the previous configuration.
             // Here we're calling Configuration#unset() instead of setToDefaults() because we
             // need to keep override configs clear of non-empty values (e.g. fontSize).
+            final Configuration currentConfig = getRequestedOverrideConfiguration();
             mTmpConfiguration.unset();
             mTmpConfiguration.updateFrom(currentConfig);
             computeScreenConfiguration(mTmpConfiguration);
@@ -1597,6 +1594,9 @@
      */
     @Rotation
     int rotationForActivityInDifferentOrientation(@NonNull ActivityRecord r) {
+        if (mTransitionController.isShellTransitionsEnabled()) {
+            return ROTATION_UNDEFINED;
+        }
         if (!WindowManagerService.ENABLE_FIXED_ROTATION_TRANSFORM) {
             return ROTATION_UNDEFINED;
         }
@@ -5914,6 +5914,30 @@
     }
 
     /**
+     * Notifies that some Keyguard flags have changed and the visibilities of the activities may
+     * need to be reevaluated.
+     */
+    void notifyKeyguardFlagsChanged() {
+        if (!isKeyguardLocked()) {
+            // If keyguard is not locked, the change of flags won't affect activity visibility.
+            return;
+        }
+        // We might change the visibilities here, so prepare an empty app transition which might be
+        // overridden later if we actually change visibilities.
+        final boolean wasTransitionSet = mAppTransition.isTransitionSet();
+        if (!wasTransitionSet) {
+            prepareAppTransition(TRANSIT_NONE);
+        }
+        mRootWindowContainer.ensureActivitiesVisible(null, 0, false /* preserveWindows */);
+
+        // If there was a transition set already we don't want to interfere with it as we might be
+        // starting it too early.
+        if (!wasTransitionSet) {
+            executeAppTransition();
+        }
+    }
+
+    /**
      * Check if the display has {@link Display#FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD} applied.
      */
     boolean canShowWithInsecureKeyguard() {
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 4768b27..49a51d5 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -1447,7 +1447,7 @@
         final InsetsStateController controller = mDisplayContent.getInsetsStateController();
         for (int i = mInsetsSourceWindowsExceptIme.size() - 1; i >= 0; i--) {
             final WindowState win = mInsetsSourceWindowsExceptIme.valueAt(i);
-            mWindowLayout.computeWindowFrames(win.getLayoutingAttrs(displayFrames.mRotation),
+            mWindowLayout.computeFrames(win.getLayoutingAttrs(displayFrames.mRotation),
                     displayFrames.mInsetsState, displayFrames.mDisplayCutoutSafe,
                     displayFrames.mUnrestricted, win.getWindowingMode(), UNSPECIFIED_LENGTH,
                     UNSPECIFIED_LENGTH, win.getRequestedVisibilities(),
@@ -1496,7 +1496,7 @@
 
         sTmpLastParentFrame.set(pf);
 
-        final boolean clippedByDisplayCutout = mWindowLayout.computeWindowFrames(attrs,
+        final boolean clippedByDisplayCutout = mWindowLayout.computeFrames(attrs,
                 win.getInsetsState(), displayFrames.mDisplayCutoutSafe,
                 win.getBounds(), win.getWindowingMode(), requestedWidth, requestedHeight,
                 win.getRequestedVisibilities(), attachedWindowFrame, win.mGlobalScale,
@@ -1710,7 +1710,8 @@
 
         if (mShowingDream != mLastShowingDream) {
             mLastShowingDream = mShowingDream;
-            mService.notifyShowingDreamChanged();
+            // Notify that isShowingDreamLw (which is checked in KeyguardController) has changed.
+            mDisplayContent.notifyKeyguardFlagsChanged();
         }
 
         mService.mPolicy.setAllowLockscreenWhenOn(getDisplayId(), mAllowLockscreenWhenOn);
@@ -2377,8 +2378,7 @@
 
     @VisibleForTesting
     int updateLightNavigationBarLw(int appearance, WindowState navColorWin) {
-        if (navColorWin == null || navColorWin.isDimming()
-                || !isLightBarAllowed(navColorWin, Type.navigationBars())) {
+        if (navColorWin == null || !isLightBarAllowed(navColorWin, Type.navigationBars())) {
             // Clear the light flag while not allowed.
             appearance &= ~APPEARANCE_LIGHT_NAVIGATION_BARS;
             return appearance;
diff --git a/services/core/java/com/android/server/wm/FadeRotationAnimationController.java b/services/core/java/com/android/server/wm/FadeRotationAnimationController.java
index bbda577..c85e04d 100644
--- a/services/core/java/com/android/server/wm/FadeRotationAnimationController.java
+++ b/services/core/java/com/android/server/wm/FadeRotationAnimationController.java
@@ -59,8 +59,13 @@
     /** The list to store the drawn tokens before the rotation animation starts. */
     private ArrayList<WindowToken> mPendingShowTokens;
 
-    /** It is used when the display has rotated, but some windows fade out in old rotation. */
-    private SeamlessRotator mRotator;
+    /**
+     * The sync transactions of the target windows. It is used when the display has rotated but
+     * the windows need to fade out in previous rotation. These transactions will be applied with
+     * fade-in animation, so there won't be a flickering such as the windows have redrawn during
+     * fading out.
+     */
+    private ArrayMap<WindowState, SurfaceControl.Transaction> mCapturedDrawTransactions;
 
     private final int mOriginalRotation;
     private final boolean mHasScreenRotationAnimation;
@@ -110,16 +115,36 @@
                 mTargetWindowTokens.put(w.mToken, null);
             }
         }, true /* traverseTopToBottom */);
+
+        // The transition sync group may be finished earlier because it doesn't wait for these
+        // target windows. But the windows still need to use sync transaction to keep the appearance
+        // in previous rotation, so request a no-op sync to keep the state.
+        if (!mIsChangeTransition && transitionType != WindowManager.TRANSIT_NONE) {
+            for (int i = mTargetWindowTokens.size() - 1; i >= 0; i--) {
+                final WindowToken token = mTargetWindowTokens.keyAt(i);
+                for (int j = token.getChildCount() - 1; j >= 0; j--) {
+                    token.getChildAt(j).applyWithNextDraw(t -> {});
+                }
+            }
+        }
     }
 
     @Override
     public void fadeWindowToken(boolean show, WindowToken windowToken, int animationType) {
         if (show) {
-            final SurfaceControl leash = mTargetWindowTokens.remove(windowToken);
-            if (leash != null && mRotator != null) {
-                // The leash was unrotated by start transaction of transition. Clear the transform
-                // to reshow the window in current rotation.
-                mRotator.setIdentityMatrix(mDisplayContent.getPendingTransaction(), leash);
+            // The previous animation leash will be dropped when preparing fade-in animation, so
+            // simply remove it without restoring the transformation.
+            mTargetWindowTokens.remove(windowToken);
+            if (mCapturedDrawTransactions != null) {
+                // Unblock the window to draw its latest content with fade-in animation.
+                final SurfaceControl.Transaction t = mDisplayContent.getPendingTransaction();
+                for (int i = windowToken.getChildCount() - 1; i >= 0; i--) {
+                    final SurfaceControl.Transaction drawT =
+                            mCapturedDrawTransactions.remove(windowToken.getChildAt(i));
+                    if (drawT != null) {
+                        t.merge(drawT);
+                    }
+                }
             }
         }
         super.fadeWindowToken(show, windowToken, animationType);
@@ -225,14 +250,14 @@
             // Take OPEN/CLOSE transition type as the example, the non-activity windows need to
             // fade out in previous rotation while display has rotated to the new rotation, so
             // their leashes are unrotated with the start transaction.
-            mRotator = new SeamlessRotator(mOriginalRotation,
+            final SeamlessRotator rotator = new SeamlessRotator(mOriginalRotation,
                     mDisplayContent.getWindowConfiguration().getRotation(),
                     mDisplayContent.getDisplayInfo(),
                     false /* applyFixedTransformationHint */);
             for (int i = mTargetWindowTokens.size() - 1; i >= 0; i--) {
                 final SurfaceControl leash = mTargetWindowTokens.valueAt(i);
                 if (leash != null) {
-                    mRotator.applyTransform(t, leash);
+                    rotator.applyTransform(t, leash);
                 }
             }
             return;
@@ -280,6 +305,25 @@
         }
     }
 
+    /** Captures the post draw transaction if the window should update with fade-in animation. */
+    boolean handleFinishDrawing(WindowState w, SurfaceControl.Transaction postDrawTransaction) {
+        if (mIsChangeTransition || !isTargetToken(w.mToken)) return false;
+        if (postDrawTransaction != null && w.mTransitionController.inTransition()) {
+            if (mCapturedDrawTransactions == null) {
+                mCapturedDrawTransactions = new ArrayMap<>();
+            }
+            final SurfaceControl.Transaction t = mCapturedDrawTransactions.get(w);
+            if (t == null) {
+                mCapturedDrawTransactions.put(w, postDrawTransaction);
+            } else {
+                t.merge(postDrawTransaction);
+            }
+            return true;
+        }
+        mDisplayContent.finishFadeRotationAnimation(w.mToken);
+        return false;
+    }
+
     @Override
     public Animation getFadeInAnimation() {
         if (mHasScreenRotationAnimation) {
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index e33c440..1a1101e 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -187,7 +187,6 @@
 
             // Navigation bar doesn't get influenced by anything else
             if (type == ITYPE_NAVIGATION_BAR || type == ITYPE_EXTRA_NAVIGATION_BAR) {
-                state.removeSource(ITYPE_IME);
                 state.removeSource(ITYPE_STATUS_BAR);
                 state.removeSource(ITYPE_CLIMATE_BAR);
                 state.removeSource(ITYPE_CAPTION_BAR);
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index c7b13eb..535bbb7 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -1817,8 +1817,7 @@
         final DisplayContent displayContent = getDisplayContent(displayId);
         Configuration config = null;
         if (displayContent != null) {
-            config = displayContent.updateOrientation(
-                    getDisplayOverrideConfiguration(displayId), starting, true /* forceUpdate */);
+            config = displayContent.updateOrientation(starting, true /* forceUpdate */);
         }
         // Visibilities may change so let the starting activity have a chance to report. Can't do it
         // when visibility is changed in each AppWindowToken because it may trigger wrong
@@ -2555,24 +2554,6 @@
         mDisplayManagerInternal.setDisplayAccessUIDs(mDisplayAccessUIDs);
     }
 
-    Configuration getDisplayOverrideConfiguration(int displayId) {
-        final DisplayContent displayContent = getDisplayContentOrCreate(displayId);
-        if (displayContent == null) {
-            throw new IllegalArgumentException("No display found with id: " + displayId);
-        }
-
-        return displayContent.getRequestedOverrideConfiguration();
-    }
-
-    void setDisplayOverrideConfiguration(Configuration overrideConfiguration, int displayId) {
-        final DisplayContent displayContent = getDisplayContentOrCreate(displayId);
-        if (displayContent == null) {
-            throw new IllegalArgumentException("No display found with id: " + displayId);
-        }
-
-        displayContent.onRequestedOverrideConfigurationChanged(overrideConfiguration);
-    }
-
     void prepareForShutdown() {
         for (int i = 0; i < getChildCount(); i++) {
             createSleepToken("shutdown", getChildAt(i).mDisplayId);
diff --git a/services/core/java/com/android/server/wm/RunningTasks.java b/services/core/java/com/android/server/wm/RunningTasks.java
index 1533245..d31b007 100644
--- a/services/core/java/com/android/server/wm/RunningTasks.java
+++ b/services/core/java/com/android/server/wm/RunningTasks.java
@@ -58,6 +58,7 @@
     private boolean mAllowed;
     private boolean mFilterOnlyVisibleRecents;
     private Task mTopDisplayFocusRootTask;
+    private Task mTopDisplayAdjacentTask;
     private RecentTasks mRecentTasks;
     private boolean mKeepIntentExtra;
 
@@ -81,6 +82,12 @@
         mRecentTasks = root.mService.getRecentTasks();
         mKeepIntentExtra = (flags & FLAG_KEEP_INTENT_EXTRA) == FLAG_KEEP_INTENT_EXTRA;
 
+        if (mTopDisplayFocusRootTask.getAdjacentTaskFragment() != null) {
+            mTopDisplayAdjacentTask = mTopDisplayFocusRootTask.getAdjacentTaskFragment().asTask();
+        } else {
+            mTopDisplayAdjacentTask = null;
+        }
+
         final PooledConsumer c = PooledLambda.obtainConsumer(RunningTasks::processTask, this,
                 PooledLambda.__(Task.class));
         root.forAllLeafTasks(c, false);
@@ -130,6 +137,12 @@
             // can be used to determine the order of the tasks (it may not be set for newly
             // created tasks)
             task.touchActiveTime();
+        } else if (rootTask == mTopDisplayAdjacentTask && rootTask.getTopMostTask() == task) {
+            // The short-term workaround for launcher could get suitable running task info in
+            // split screen.
+            task.touchActiveTime();
+            // TreeSet doesn't allow same value and make sure this task is lower than focus one.
+            task.lastActiveTime--;
         }
 
         mTmpSortedSet.add(task);
diff --git a/services/core/java/com/android/server/wm/SplashScreenExceptionList.java b/services/core/java/com/android/server/wm/SplashScreenExceptionList.java
index e815a0e..9ca49fe 100644
--- a/services/core/java/com/android/server/wm/SplashScreenExceptionList.java
+++ b/services/core/java/com/android/server/wm/SplashScreenExceptionList.java
@@ -64,7 +64,8 @@
                 mOnPropertiesChangedListener);
     }
 
-    private void updateDeviceConfig(String values) {
+    @VisibleForTesting
+    void updateDeviceConfig(String values) {
         parseDeviceConfigPackageList(values);
     }
 
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 7c3432e..659c771 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -319,6 +319,11 @@
      */
     boolean mInResumeTopActivity = false;
 
+    /**
+     * Used to identify if the activity that is installed from device's system image.
+     */
+    boolean mIsEffectivelySystemApp;
+
     int mCurrentUser;
 
     String affinity;        // The affinity name for this task, or null; may change identity.
@@ -554,13 +559,24 @@
 
             if (r.finishing) return false;
 
-            // Set this as the candidate root since it isn't finishing.
-            mRoot = r;
+            if (mRoot == null || mRoot.finishing) {
+                // Set this as the candidate root since it isn't finishing.
+                mRoot = r;
+            }
 
-            // Only end search if we are ignore relinquishing identity or we are not relinquishing.
-            return mIgnoreRelinquishIdentity
-                    || mNeverRelinquishIdentity
-                    || (r.info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0;
+            final int uid = mRoot == r ? effectiveUid : r.info.applicationInfo.uid;
+            if (mIgnoreRelinquishIdentity
+                    || (mRoot.info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0
+                    || (mRoot.info.applicationInfo.uid != Process.SYSTEM_UID
+                    && !mRoot.info.applicationInfo.isSystemApp()
+                    && mRoot.info.applicationInfo.uid != uid)) {
+                // No need to relinquish identity, end search.
+                return true;
+            }
+
+            // Relinquish to next activity
+            mRoot = r;
+            return false;
         }
     }
 
@@ -985,7 +1001,15 @@
      * @param info The activity info which could be different from {@code r.info} if set.
      */
     void setIntent(ActivityRecord r, @Nullable Intent intent, @Nullable ActivityInfo info) {
-        if (this.intent == null || !mNeverRelinquishIdentity) {
+        boolean updateIdentity = false;
+        if (this.intent == null) {
+            updateIdentity = true;
+        } else if (!mNeverRelinquishIdentity) {
+            final ActivityInfo activityInfo = info != null ? info : r.info;
+            updateIdentity = (effectiveUid == Process.SYSTEM_UID || mIsEffectivelySystemApp
+                    || effectiveUid == activityInfo.applicationInfo.uid);
+        }
+        if (updateIdentity) {
             mCallingUid = r.launchedFromUid;
             mCallingPackage = r.launchedFromPackage;
             mCallingFeatureId = r.launchedFromFeatureId;
@@ -998,14 +1022,7 @@
     private void setIntent(Intent _intent, ActivityInfo info) {
         if (!isLeafTask()) return;
 
-        if (info.applicationInfo.uid == Process.SYSTEM_UID
-                || info.applicationInfo.isSystemApp()) {
-            // Only allow the apps that pre-installed on the system image to apply
-            // relinquishTaskIdentity
-            mNeverRelinquishIdentity = (info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0;
-        } else {
-            mNeverRelinquishIdentity = true;
-        }
+        mNeverRelinquishIdentity = (info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0;
         affinity = info.taskAffinity;
         if (intent == null) {
             // If this task already has an intent associated with it, don't set the root
@@ -1014,6 +1031,7 @@
             rootAffinity = affinity;
         }
         effectiveUid = info.applicationInfo.uid;
+        mIsEffectivelySystemApp = info.applicationInfo.isSystemApp();
         stringName = null;
 
         if (info.targetActivity == null) {
@@ -4976,8 +4994,7 @@
             if (topFragment == f) {
                 return;
             }
-            if (!f.isFocusableAndVisible()) {
-                // No need to resume activity in TaskFragment that is not visible.
+            if (!f.canBeResumed(null /* starting */)) {
                 return;
             }
             resumed[0] |= f.resumeTopActivity(prev, options, deferPause);
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index 796a90a..dfb559f 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -38,7 +38,6 @@
 import static com.android.server.wm.ActivityRecord.State.RESUMED;
 import static com.android.server.wm.ActivityTaskManagerService.TAG_ROOT_TASK;
 import static com.android.server.wm.DisplayContent.alwaysCreateRootTask;
-import static com.android.server.wm.TaskFragment.TASK_FRAGMENT_VISIBILITY_VISIBLE;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ROOT_TASK;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
@@ -1407,9 +1406,7 @@
 
             leafTask.forAllLeafTaskFragments((taskFrag) -> {
                 final ActivityRecord resumedActivity = taskFrag.getResumedActivity();
-                if (resumedActivity != null
-                        && (taskFrag.getVisibility(resuming) != TASK_FRAGMENT_VISIBILITY_VISIBLE
-                        || !taskFrag.isTopActivityFocusable())) {
+                if (resumedActivity != null && !taskFrag.canBeResumed(resuming)) {
                     if (taskFrag.startPausing(false /* uiSleeping*/, resuming, "pauseBackTasks")) {
                         someActivityPaused[0]++;
                     }
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 97cb512..8299cea 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -1355,6 +1355,17 @@
         return getVisibility(starting) != TASK_FRAGMENT_VISIBILITY_INVISIBLE;
     }
 
+    /**
+     * Returns {@code true} is the activity in this TaskFragment can be resumed.
+     *
+     * @param starting The currently starting activity or {@code null} if there is none.
+     */
+    boolean canBeResumed(@Nullable ActivityRecord starting) {
+        // No need to resume activity in TaskFragment that is not visible.
+        return isTopActivityFocusable()
+                && getVisibility(starting) == TASK_FRAGMENT_VISIBILITY_VISIBLE;
+    }
+
     boolean isFocusableAndVisible() {
         return isTopActivityFocusable() && shouldBeVisible(null /* starting */);
     }
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index c6948ee..a477108 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -20,11 +20,13 @@
 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.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 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.LayoutParams.TYPE_APPLICATION_STARTING;
 import static android.view.WindowManager.TRANSIT_CHANGE;
 import static android.view.WindowManager.TRANSIT_CLOSE;
 import static android.view.WindowManager.TRANSIT_FLAG_IS_RECENTS;
@@ -66,10 +68,12 @@
 import android.os.IRemoteCallback;
 import android.os.RemoteException;
 import android.os.SystemClock;
+import android.os.Trace;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Slog;
 import android.view.SurfaceControl;
+import android.view.WindowManager;
 import android.view.animation.Animation;
 import android.window.RemoteTransition;
 import android.window.TransitionInfo;
@@ -82,6 +86,8 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Predicate;
 
 /**
  * Represents a logical transition.
@@ -89,6 +95,10 @@
  */
 class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListener {
     private static final String TAG = "Transition";
+    private static final String TRACE_NAME_PLAY_TRANSITION = "PlayTransition";
+
+    /** The default package for resources */
+    private static final String DEFAULT_PACKAGE = "android";
 
     /** The transition has been created and is collecting, but hasn't formally started. */
     private static final int STATE_COLLECTING = 0;
@@ -174,7 +184,7 @@
         mFlags = flags;
         mController = controller;
         mSyncEngine = syncEngine;
-        mSyncId = mSyncEngine.startSyncSet(this, timeoutMs);
+        mSyncId = mSyncEngine.startSyncSet(this, timeoutMs, TAG);
     }
 
     void addFlag(int flag) {
@@ -395,6 +405,10 @@
      * be called directly; use {@link TransitionController#finishTransition} instead.
      */
     void finishTransition() {
+        if (Trace.isTagEnabled(TRACE_TAG_WINDOW_MANAGER)) {
+            Trace.asyncTraceEnd(TRACE_TAG_WINDOW_MANAGER, TRACE_NAME_PLAY_TRANSITION,
+                    System.identityHashCode(this));
+        }
         mStartTransaction = mFinishTransaction = null;
         if (mState < STATE_PLAYING) {
             throw new IllegalStateException("Can't finish a non-playing transition " + mSyncId);
@@ -483,6 +497,11 @@
         if (fadeRotationController != null) {
             fadeRotationController.onTransitionFinished();
         }
+        // Transient-launch activities cannot be IME target (WindowState#canBeImeTarget),
+        // so re-compute in case the IME target is changed after transition.
+        if (mTransientLaunches != null) {
+            mTargetDisplay.computeImeTarget(true /* updateImeTarget */);
+        }
     }
 
     void abort() {
@@ -548,7 +567,9 @@
         // Resolve the animating targets from the participants
         mTargets = calculateTargets(mParticipants, mChanges);
         final TransitionInfo info = calculateTransitionInfo(mType, mFlags, mTargets, mChanges);
-        info.setAnimationOptions(mOverrideOptions);
+        if (mOverrideOptions != null) {
+            info.setAnimationOptions(mOverrideOptions);
+        }
 
         // TODO(b/188669821): Move to animation impl in shell.
         handleLegacyRecentsStartBehavior(dc, info);
@@ -630,6 +651,10 @@
                         "Calling onTransitionReady: %s", info);
                 mController.getTransitionPlayer().onTransitionReady(
                         this, info, transaction, mFinishTransaction);
+                if (Trace.isTagEnabled(TRACE_TAG_WINDOW_MANAGER)) {
+                    Trace.asyncTraceBegin(TRACE_TAG_WINDOW_MANAGER, TRACE_NAME_PLAY_TRANSITION,
+                            System.identityHashCode(this));
+                }
             } catch (RemoteException e) {
                 // If there's an exception when trying to send the mergedTransaction to the
                 // client, we should finish and apply it here so the transactions aren't lost.
@@ -1249,9 +1274,80 @@
             out.addChange(change);
         }
 
+        final WindowManager.LayoutParams animLp =
+                getLayoutParamsForAnimationsStyle(type, sortedTargets);
+        if (animLp != null && animLp.type != TYPE_APPLICATION_STARTING
+                && animLp.windowAnimations != 0) {
+            // Don't send animation options if no windowAnimations have been set or if the we are
+            // running an app starting animation, in which case we don't want the app to be able to
+            // change its animation directly.
+            TransitionInfo.AnimationOptions animOptions =
+                    TransitionInfo.AnimationOptions.makeAnimOptionsFromLayoutParameters(animLp);
+            out.setAnimationOptions(animOptions);
+        }
+
         return out;
     }
 
+    private static WindowManager.LayoutParams getLayoutParamsForAnimationsStyle(int type,
+            ArrayList<WindowContainer> sortedTargets) {
+        // Find the layout params of the top-most application window that is part of the
+        // transition, which is what will control the animation theme.
+        final ArraySet<Integer> activityTypes = new ArraySet<>();
+        for (WindowContainer target : sortedTargets) {
+            if (target.asActivityRecord() != null) {
+                activityTypes.add(target.getActivityType());
+            } else if (target.asWindowToken() == null && target.asWindowState() == null) {
+                // We don't want app to customize animations that are not activity to activity.
+                // Activity-level transitions can only include activities, wallpaper and subwindows.
+                // Anything else is not a WindowToken nor a WindowState and is "higher" in the
+                // hierarchy which means we are no longer in an activity transition.
+                return null;
+            }
+        }
+        if (activityTypes.isEmpty()) {
+            // We don't want app to be able to customize transitions that are not activity to
+            // activity through the layout parameter animation style.
+            return null;
+        }
+        final ActivityRecord animLpActivity =
+                findAnimLayoutParamsActivityRecord(sortedTargets, type, activityTypes);
+        final WindowState mainWindow = animLpActivity != null
+                ? animLpActivity.findMainWindow() : null;
+        return mainWindow != null ? mainWindow.mAttrs : null;
+    }
+
+    private static ActivityRecord findAnimLayoutParamsActivityRecord(
+            List<WindowContainer> sortedTargets,
+            @TransitionType int transit, ArraySet<Integer> activityTypes) {
+        // Remote animations always win, but fullscreen windows override non-fullscreen windows.
+        ActivityRecord result = lookForTopWindowWithFilter(sortedTargets,
+                w -> w.getRemoteAnimationDefinition() != null
+                    && w.getRemoteAnimationDefinition().hasTransition(transit, activityTypes));
+        if (result != null) {
+            return result;
+        }
+        result = lookForTopWindowWithFilter(sortedTargets,
+                w -> w.fillsParent() && w.findMainWindow() != null);
+        if (result != null) {
+            return result;
+        }
+        return lookForTopWindowWithFilter(sortedTargets, w -> w.findMainWindow() != null);
+    }
+
+    private static ActivityRecord lookForTopWindowWithFilter(List<WindowContainer> sortedTargets,
+            Predicate<ActivityRecord> filter) {
+        for (WindowContainer target : sortedTargets) {
+            final ActivityRecord activityRecord = target.asTaskFragment() != null
+                    ? target.asTaskFragment().getTopNonFinishingActivity()
+                    : target.asActivityRecord();
+            if (activityRecord != null && filter.test(activityRecord)) {
+                return activityRecord;
+            }
+        }
+        return null;
+    }
+
     private static int getTaskRotationAnimation(@NonNull Task task) {
         final ActivityRecord top = task.getTopVisibleActivity();
         if (top == null) return ROTATION_ANIMATION_UNSPECIFIED;
diff --git a/services/core/java/com/android/server/wm/UnknownAppVisibilityController.java b/services/core/java/com/android/server/wm/UnknownAppVisibilityController.java
index 4007661..5e963cc 100644
--- a/services/core/java/com/android/server/wm/UnknownAppVisibilityController.java
+++ b/services/core/java/com/android/server/wm/UnknownAppVisibilityController.java
@@ -135,8 +135,8 @@
         int state = mUnknownApps.get(activity);
         if (state == UNKNOWN_STATE_WAITING_RELAYOUT || activity.mStartingWindow != null) {
             mUnknownApps.put(activity, UNKNOWN_STATE_WAITING_VISIBILITY_UPDATE);
-            mService.notifyKeyguardFlagsChanged(this::notifyVisibilitiesUpdated,
-                    activity.getDisplayContent().getDisplayId());
+            mDisplayContent.notifyKeyguardFlagsChanged();
+            notifyVisibilitiesUpdated();
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index e24be37..24493e2 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -298,9 +298,9 @@
     }
 
     boolean updateWallpaperOffset(WindowState wallpaperWin, boolean sync) {
-        final Rect parentFrame = wallpaperWin.getParentFrame();
-        final int dw = parentFrame.width();
-        final int dh = parentFrame.height();
+        final Rect bounds = wallpaperWin.getLastReportedBounds();
+        final int dw = bounds.width();
+        final int dh = bounds.height();
 
         int xOffset = 0;
         int yOffset = 0;
@@ -448,6 +448,13 @@
 
     private void updateWallpaperOffsetLocked(WindowState changingTarget, boolean sync) {
         WindowState target = mWallpaperTarget;
+        if (target == null && changingTarget.mToken.isVisible()
+                && changingTarget.mTransitionController.inTransition()) {
+            // If the wallpaper target was cleared during transition, still allows the visible
+            // window which may have been requested to be invisible to update the offset, e.g.
+            // zoom effect from home.
+            target = changingTarget;
+        }
         if (target != null) {
             if (target.mWallpaperX >= 0) {
                 mLastWallpaperX = target.mWallpaperX;
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 7e84dbb..61acb97 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -3181,6 +3181,11 @@
     }
 
     /** Cheap way of doing cast and instanceof. */
+    WindowState asWindowState() {
+        return null;
+    }
+
+    /** Cheap way of doing cast and instanceof. */
     ActivityRecord asActivityRecord() {
         return null;
     }
@@ -3349,8 +3354,12 @@
         for (int i = mChildren.size() - 1; i >= 0; --i) {
             mChildren.get(i).finishSync(outMergedTransaction, cancel);
         }
-        mSyncState = SYNC_STATE_NONE;
         if (cancel && mSyncGroup != null) mSyncGroup.onCancelSync(this);
+        clearSyncState();
+    }
+
+    void clearSyncState() {
+        mSyncState = SYNC_STATE_NONE;
         mSyncGroup = null;
     }
 
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 86775f6..7be128b 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -60,6 +60,7 @@
 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.INPUT_FEATURE_SPY;
 import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE;
 import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
 import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
@@ -1653,6 +1654,8 @@
             final DisplayPolicy displayPolicy = displayContent.getDisplayPolicy();
             displayPolicy.adjustWindowParamsLw(win, win.mAttrs);
             attrs.flags = sanitizeFlagSlippery(attrs.flags, win.getName(), callingUid, callingPid);
+            attrs.inputFeatures = sanitizeSpyWindow(attrs.inputFeatures, win.getName(), callingUid,
+                    callingPid);
             win.setRequestedVisibilities(requestedVisibilities);
 
             res = displayPolicy.validateAddingWindowLw(attrs, callingPid, callingUid);
@@ -2211,6 +2214,8 @@
                 displayPolicy.adjustWindowParamsLw(win, attrs);
                 win.mToken.adjustWindowParams(win, attrs);
                 attrs.flags = sanitizeFlagSlippery(attrs.flags, win.getName(), uid, pid);
+                attrs.inputFeatures = sanitizeSpyWindow(attrs.inputFeatures, win.getName(), uid,
+                        pid);
                 int disableFlags =
                         (attrs.systemUiVisibility | attrs.subtreeSystemUiVisibility) & DISABLE_MASK;
                 if (disableFlags != 0 && !hasStatusBarPermission(pid, uid)) {
@@ -2543,10 +2548,8 @@
         if (win.mAttrs.type == TYPE_APPLICATION_STARTING) {
             transit = WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
         }
-        if (win.inTransition()) {
-            focusMayChange = true;
-            win.mAnimatingExit = true;
-        } else if (win.isWinVisibleLw() && winAnimator.applyAnimationLocked(transit, false)) {
+
+        if (win.isWinVisibleLw() && winAnimator.applyAnimationLocked(transit, false)) {
             focusMayChange = true;
             win.mAnimatingExit = true;
         } else if (win.mDisplayContent.okToAnimate() && win.isAnimating(TRANSITION | PARENTS,
@@ -3026,17 +3029,13 @@
                 aspectRatio);
     }
 
-    /**
-     * Notifies window manager that {@link DisplayPolicy#isShowingDreamLw} has changed.
-     */
-    public void notifyShowingDreamChanged() {
-        // TODO(multi-display): support show dream in multi-display.
-        notifyKeyguardFlagsChanged(null /* callback */, DEFAULT_DISPLAY);
-    }
-
     @Override
     public void notifyKeyguardTrustedChanged() {
-        mAtmInternal.notifyKeyguardTrustedChanged();
+        synchronized (mGlobalLock) {
+            if (mAtmService.mKeyguardController.isKeyguardShowing(DEFAULT_DISPLAY)) {
+                mRoot.ensureActivitiesVisible(null, 0, false /* preserveWindows */);
+            }
+        }
     }
 
     @Override
@@ -3088,15 +3087,6 @@
         return getDefaultDisplayContentLocked().mAppTransition.isIdle();
     }
 
-    /**
-     * Notifies activity manager that some Keyguard flags have changed and that it needs to
-     * reevaluate the visibilities of the activities.
-     * @param callback Runnable to be called when activity manager is done reevaluating visibilities
-     */
-    void notifyKeyguardFlagsChanged(@Nullable Runnable callback, int displayId) {
-        mAtmInternal.notifyKeyguardFlagsChanged(callback, displayId);
-    }
-
 
     // -------------------------------------------------------------
     // Misc IWindowSession methods
@@ -8241,6 +8231,23 @@
     }
 
     /**
+     * You need MONITOR_INPUT permission to be able to set INPUT_FEATURE_SPY.
+     */
+    private int sanitizeSpyWindow(int inputFeatures, String windowName, int callingUid,
+            int callingPid) {
+        if ((inputFeatures & INPUT_FEATURE_SPY) == 0) {
+            return inputFeatures;
+        }
+        final int permissionResult = mContext.checkPermission(
+                permission.MONITOR_INPUT, callingPid, callingUid);
+        if (permissionResult != PackageManager.PERMISSION_GRANTED) {
+            throw new IllegalArgumentException("Cannot use INPUT_FEATURE_SPY from '" + windowName
+                    + "' because it doesn't the have MONITOR_INPUT permission");
+        }
+        return inputFeatures;
+    }
+
+    /**
      * Assigns an InputChannel to a SurfaceControl and configures it to receive
      * touch input according to it's on-screen geometry.
      *
@@ -8293,6 +8300,7 @@
         h.ownerUid = callingUid;
         h.ownerPid = callingPid;
 
+        // Do not allow any input features to be set without sanitizing them first.
         h.inputFeatures = 0;
 
         if (region == null) {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 0b91742..573ff2f 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -844,6 +844,11 @@
         }
     };
 
+    @Override
+    WindowState asWindowState() {
+        return this;
+    }
+
     /**
      * @see #setSurfaceTranslationY(int)
      */
@@ -2542,7 +2547,8 @@
 
         if (DEBUG_INPUT_METHOD) {
             Slog.i(TAG_WM, "isVisibleRequestedOrAdding " + this + ": "
-                    + isVisibleRequestedOrAdding());
+                    + isVisibleRequestedOrAdding() + " isVisible: " + (isVisible()
+                    && mActivityRecord != null && mActivityRecord.isVisible()));
             if (!isVisibleRequestedOrAdding()) {
                 Slog.i(TAG_WM, "  mSurfaceController=" + mWinAnimator.mSurfaceController
                         + " relayoutCalled=" + mRelayoutCalled
@@ -2557,7 +2563,8 @@
                 }
             }
         }
-        return isVisibleRequestedOrAdding();
+        return isVisibleRequestedOrAdding()
+                || (isVisible() && mActivityRecord != null && mActivityRecord.isVisible());
     }
 
     private final class DeadWindowEventReceiver extends InputEventReceiver {
@@ -2882,6 +2889,12 @@
         return mLastReportedConfiguration.getMergedConfiguration();
     }
 
+    /** Returns the last window configuration bounds reported to the client. */
+    Rect getLastReportedBounds() {
+        final Rect bounds = getLastReportedConfiguration().windowConfiguration.getBounds();
+        return !bounds.isEmpty() ? bounds : getBounds();
+    }
+
     void adjustStartingWindowFlags() {
         if (mAttrs.type == TYPE_BASE_APPLICATION && mActivityRecord != null
                 && mActivityRecord.mStartingWindow != null) {
@@ -5230,6 +5243,11 @@
             // Child window follows parent's scale.
             return;
         }
+        if (!isVisibleRequested() && !(mIsWallpaper && mToken.isVisible())) {
+            // Skip if it is requested to be invisible, but if it is wallpaper, it may be in
+            // transition that still needs to update the scale for zoom effect.
+            return;
+        }
         float newHScale = mHScale * mGlobalScale * mWallpaperScale;
         float newVScale = mVScale * mGlobalScale * mWallpaperScale;
         if (mLastHScale != newHScale ||
@@ -5249,7 +5267,7 @@
         updateSurfacePositionNonOrganized();
         // Send information to SurfaceFlinger about the priority of the current window.
         updateFrameRateSelectionPriorityIfNeeded();
-        if (isVisibleRequested()) updateScaleIfNeeded();
+        updateScaleIfNeeded();
 
         mWinAnimator.prepareSurfaceLocked(getSyncTransaction());
         super.prepareSurfaces();
@@ -5275,11 +5293,11 @@
                 mSurfacePosition);
 
         if (mWallpaperScale != 1f) {
-            DisplayInfo displayInfo = getDisplayInfo();
+            final Rect bounds = getLastReportedBounds();
             Matrix matrix = mTmpMatrix;
             matrix.setTranslate(mXOffset, mYOffset);
-            matrix.postScale(mWallpaperScale, mWallpaperScale, displayInfo.logicalWidth / 2f,
-                displayInfo.logicalHeight / 2f);
+            matrix.postScale(mWallpaperScale, mWallpaperScale, bounds.exactCenterX(),
+                    bounds.exactCenterY());
             matrix.getValues(mTmpMatrixArray);
             mSurfacePosition.offset(Math.round(mTmpMatrixArray[Matrix.MTRANS_X]),
                 Math.round(mTmpMatrixArray[Matrix.MTRANS_Y]));
@@ -5411,7 +5429,7 @@
 
     @Override
     void assignLayer(Transaction t, int layer) {
-        if (isStartingWindowAssociatedToTask()) {
+        if (mStartingData != null) {
             // The starting window should cover the task.
             t.setLayer(mSurfaceControl, Integer.MAX_VALUE);
             return;
@@ -5731,29 +5749,36 @@
             Slog.i(TAG, "finishDrawing of relaunch: " + this + " " + duration + "ms");
             mActivityRecord.mRelaunchStartTime = 0;
         }
-
-        executeDrawHandlers(postDrawTransaction);
-
-        final boolean applyPostDrawNow = mClientWasDrawingForSync && postDrawTransaction != null;
-        mClientWasDrawingForSync = false;
-        if (!onSyncFinishedDrawing()) {
-            return mWinAnimator.finishDrawingLocked(postDrawTransaction, applyPostDrawNow);
-        }
-
-        if (mActivityRecord != null
-                && mTransitionController.isShellTransitionsEnabled()
-                && mAttrs.type == TYPE_APPLICATION_STARTING) {
+        if (mActivityRecord != null && mAttrs.type == TYPE_APPLICATION_STARTING) {
             mWmService.mAtmService.mTaskSupervisor.getActivityMetricsLogger()
                     .notifyStartingWindowDrawn(mActivityRecord);
         }
 
-        if (postDrawTransaction != null) {
+        final boolean hasSyncHandlers = executeDrawHandlers(postDrawTransaction);
+
+        boolean skipLayout = false;
+        // Control the timing to switch the appearance of window with different rotations.
+        final FadeRotationAnimationController fadeRotationController =
+                mDisplayContent.getFadeRotationAnimationController();
+        if (fadeRotationController != null
+                && fadeRotationController.handleFinishDrawing(this, postDrawTransaction)) {
+            // Consume the transaction because the controller will apply it with fade animation.
+            // Layout is not needed because the window will be hidden by the fade leash. Clear
+            // sync state because its sync transaction doesn't need to be merged to sync group.
+            postDrawTransaction = null;
+            skipLayout = true;
+            clearSyncState();
+        } else if (onSyncFinishedDrawing() && postDrawTransaction != null) {
             mSyncTransaction.merge(postDrawTransaction);
+            // Consume the transaction because the sync group will merge it.
+            postDrawTransaction = null;
         }
 
-        mWinAnimator.finishDrawingLocked(null, false /* forceApplyNow */);
+        final boolean layoutNeeded =
+                mWinAnimator.finishDrawingLocked(postDrawTransaction, mClientWasDrawingForSync);
+        mClientWasDrawingForSync = false;
         // We always want to force a traversal after a finish draw for blast sync.
-        return true;
+        return !skipLayout && (hasSyncHandlers || layoutNeeded);
     }
 
     void immediatelyNotifyBlastSync() {
diff --git a/services/core/jni/com_android_server_ConsumerIrService.cpp b/services/core/jni/com_android_server_ConsumerIrService.cpp
index 2ca348b..63daa35 100644
--- a/services/core/jni/com_android_server_ConsumerIrService.cpp
+++ b/services/core/jni/com_android_server_ConsumerIrService.cpp
@@ -34,7 +34,7 @@
 
 static sp<IConsumerIr> mHal;
 
-static jboolean halOpen(JNIEnv* /* env */, jobject /* obj */) {
+static jboolean getHidlHalService(JNIEnv * /* env */, jobject /* obj */) {
     // TODO(b/31632518)
     mHal = IConsumerIr::getService();
     return mHal != nullptr;
@@ -84,9 +84,9 @@
 }
 
 static const JNINativeMethod method_table[] = {
-    { "halOpen", "()Z", (void *)halOpen },
-    { "halTransmit", "(I[I)I", (void *)halTransmit },
-    { "halGetCarrierFrequencies", "()[I", (void *)halGetCarrierFrequencies},
+        {"getHidlHalService", "()Z", (void *)getHidlHalService},
+        {"halTransmit", "(I[I)I", (void *)halTransmit},
+        {"halGetCarrierFrequencies", "()[I", (void *)halGetCarrierFrequencies},
 };
 
 int register_android_server_ConsumerIrService(JNIEnv *env) {
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index c5a69e2..3cd4e5e 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -1595,7 +1595,7 @@
 
     if (!inputChannel.ok()) {
         std::string message = inputChannel.error().message();
-        message += StringPrintf(" Status=%d", inputChannel.error().code());
+        message += StringPrintf(" Status=%d", static_cast<int>(inputChannel.error().code()));
         jniThrowRuntimeException(env, message.c_str());
         return nullptr;
     }
@@ -1629,7 +1629,7 @@
 
     if (!inputChannel.ok()) {
         std::string message = inputChannel.error().message();
-        message += StringPrintf(" Status=%d", inputChannel.error().code());
+        message += StringPrintf(" Status=%d", static_cast<int>(inputChannel.error().code()));
         jniThrowRuntimeException(env, message.c_str());
         return nullptr;
     }
@@ -2292,6 +2292,11 @@
                                                                       sensorType));
 }
 
+static void nativeCancelCurrentTouch(JNIEnv* env, jclass /* clazz */, jlong ptr) {
+    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+    im->getInputManager()->getDispatcher().cancelCurrentTouch();
+}
+
 // ----------------------------------------------------------------------------
 
 static const JNINativeMethod gInputManagerMethods[] = {
@@ -2371,6 +2376,7 @@
         {"nativeEnableSensor", "(JIIII)Z", (void*)nativeEnableSensor},
         {"nativeDisableSensor", "(JII)V", (void*)nativeDisableSensor},
         {"nativeFlushSensor", "(JII)Z", (void*)nativeFlushSensor},
+        {"nativeCancelCurrentTouch", "(J)V", (void*)nativeCancelCurrentTouch},
 };
 
 #define FIND_CLASS(var, className) \
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index f0f779d..be656e3 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -29,6 +29,7 @@
 #include <android/hardware/gnss/2.1/IGnssMeasurement.h>
 #include <android/hardware/gnss/BnGnss.h>
 #include <android/hardware/gnss/BnGnssCallback.h>
+#include <android/hardware/gnss/BnGnssDebug.h>
 #include <android/hardware/gnss/BnGnssGeofence.h>
 #include <android/hardware/gnss/BnGnssGeofenceCallback.h>
 #include <android/hardware/gnss/BnGnssMeasurementCallback.h>
@@ -53,6 +54,7 @@
 #include "gnss/GnssAntennaInfoCallback.h"
 #include "gnss/GnssBatching.h"
 #include "gnss/GnssConfiguration.h"
+#include "gnss/GnssDebug.h"
 #include "gnss/GnssGeofence.h"
 #include "gnss/GnssMeasurement.h"
 #include "gnss/GnssNavigationMessage.h"
@@ -155,8 +157,6 @@
 using IGnssCallback_V1_0 = android::hardware::gnss::V1_0::IGnssCallback;
 using IGnssCallback_V2_0 = android::hardware::gnss::V2_0::IGnssCallback;
 using IGnssCallback_V2_1 = android::hardware::gnss::V2_1::IGnssCallback;
-using IGnssDebug_V1_0 = android::hardware::gnss::V1_0::IGnssDebug;
-using IGnssDebug_V2_0 = android::hardware::gnss::V2_0::IGnssDebug;
 using IGnssAntennaInfo = android::hardware::gnss::V2_1::IGnssAntennaInfo;
 using IAGnssRil_V1_0 = android::hardware::gnss::V1_0::IAGnssRil;
 using IAGnssRil_V2_0 = android::hardware::gnss::V2_0::IAGnssRil;
@@ -179,6 +179,7 @@
 using IGnssAidl = android::hardware::gnss::IGnss;
 using IGnssCallbackAidl = android::hardware::gnss::IGnssCallback;
 using IGnssBatchingAidl = android::hardware::gnss::IGnssBatching;
+using IGnssDebugAidl = android::hardware::gnss::IGnssDebug;
 using IGnssPsdsAidl = android::hardware::gnss::IGnssPsds;
 using IGnssPsdsCallbackAidl = android::hardware::gnss::IGnssPsdsCallback;
 using IGnssConfigurationAidl = android::hardware::gnss::IGnssConfiguration;
@@ -209,8 +210,6 @@
 sp<IGnssXtra> gnssXtraIface = nullptr;
 sp<IAGnssRil_V1_0> agnssRilIface = nullptr;
 sp<IAGnssRil_V2_0> agnssRilIface_V2_0 = nullptr;
-sp<IGnssDebug_V1_0> gnssDebugIface = nullptr;
-sp<IGnssDebug_V2_0> gnssDebugIface_V2_0 = nullptr;
 sp<IGnssNi> gnssNiIface = nullptr;
 sp<IGnssPowerIndication> gnssPowerIndicationIface = nullptr;
 sp<IMeasurementCorrections_V1_0> gnssCorrectionsIface_V1_0 = nullptr;
@@ -224,6 +223,7 @@
 std::unique_ptr<android::gnss::GnssBatchingInterface> gnssBatchingIface = nullptr;
 std::unique_ptr<android::gnss::GnssGeofenceInterface> gnssGeofencingIface = nullptr;
 std::unique_ptr<android::gnss::AGnssInterface> agnssIface = nullptr;
+std::unique_ptr<android::gnss::GnssDebugInterface> gnssDebugIface = nullptr;
 
 #define WAKE_LOCK_NAME  "GPS"
 
@@ -232,6 +232,11 @@
 namespace {
 
 // Returns true if location has lat/long information.
+bool hasLatLong(const GnssLocationAidl& location) {
+    return (location.gnssLocationFlags & GnssLocationAidl::HAS_LAT_LONG) != 0;
+}
+
+// Returns true if location has lat/long information.
 bool hasLatLong(const GnssLocation_V1_0& location) {
     return (static_cast<uint32_t>(location.gnssLocationFlags) &
             GnssLocationFlags::HAS_LAT_LONG) != 0;
@@ -248,6 +253,36 @@
     return value ? JNI_TRUE : JNI_FALSE;
 }
 
+static GnssLocationAidl createGnssLocation(jint gnssLocationFlags, jdouble latitudeDegrees,
+                                           jdouble longitudeDegrees, jdouble altitudeMeters,
+                                           jfloat speedMetersPerSec, jfloat bearingDegrees,
+                                           jfloat horizontalAccuracyMeters,
+                                           jfloat verticalAccuracyMeters,
+                                           jfloat speedAccuracyMetersPerSecond,
+                                           jfloat bearingAccuracyDegrees, jlong timestamp,
+                                           jint elapsedRealtimeFlags, jlong elapsedRealtimeNanos,
+                                           jdouble elapsedRealtimeUncertaintyNanos) {
+    GnssLocationAidl location;
+    location.gnssLocationFlags = static_cast<int>(gnssLocationFlags);
+    location.latitudeDegrees = static_cast<double>(latitudeDegrees);
+    location.longitudeDegrees = static_cast<double>(longitudeDegrees);
+    location.altitudeMeters = static_cast<double>(altitudeMeters);
+    location.speedMetersPerSec = static_cast<double>(speedMetersPerSec);
+    location.bearingDegrees = static_cast<double>(bearingDegrees);
+    location.horizontalAccuracyMeters = static_cast<double>(horizontalAccuracyMeters);
+    location.verticalAccuracyMeters = static_cast<double>(verticalAccuracyMeters);
+    location.speedAccuracyMetersPerSecond = static_cast<double>(speedAccuracyMetersPerSecond);
+    location.bearingAccuracyDegrees = static_cast<double>(bearingAccuracyDegrees);
+    location.timestampMillis = static_cast<uint64_t>(timestamp);
+
+    location.elapsedRealtime.flags = static_cast<int>(elapsedRealtimeFlags);
+    location.elapsedRealtime.timestampNs = static_cast<uint64_t>(elapsedRealtimeNanos);
+    location.elapsedRealtime.timeUncertaintyNs =
+            static_cast<double>(elapsedRealtimeUncertaintyNanos);
+
+    return location;
+}
+
 static GnssLocation_V1_0 createGnssLocation_V1_0(
         jint gnssLocationFlags, jdouble latitudeDegrees, jdouble longitudeDegrees,
         jdouble altitudeMeters, jfloat speedMetersPerSec, jfloat bearingDegrees,
@@ -298,7 +333,8 @@
     Return<void> gnssLocationCb(const GnssLocation_V1_0& location) override;
     Return<void> gnssStatusCb(const IGnssCallback_V1_0::GnssStatusValue status) override;
     Return<void> gnssSvStatusCb(const IGnssCallback_V1_0::GnssSvStatus& svStatus) override {
-        return gnssSvStatusCbImpl(svStatus);
+        return gnssSvStatusCbImpl<IGnssCallback_V1_0::GnssSvStatus, IGnssCallback_V1_0::GnssSvInfo>(
+                svStatus);
     }
     Return<void> gnssNmeaCb(int64_t timestamp, const android::hardware::hidl_string& nmea) override;
     Return<void> gnssSetCapabilitesCb(uint32_t capabilities) override;
@@ -318,73 +354,67 @@
     Return<void> gnssSetCapabilitiesCb_2_0(uint32_t capabilities) override;
     Return<void> gnssLocationCb_2_0(const GnssLocation_V2_0& location) override;
     Return<void> gnssSvStatusCb_2_0(const hidl_vec<IGnssCallback_V2_0::GnssSvInfo>& svInfoList) override {
-        return gnssSvStatusCbImpl(svInfoList);
+        return gnssSvStatusCbImpl<hidl_vec<IGnssCallback_V2_0::GnssSvInfo>,
+                                  IGnssCallback_V1_0::GnssSvInfo>(svInfoList);
     }
 
     // New in 2.1
     Return<void> gnssSvStatusCb_2_1(const hidl_vec<IGnssCallback_V2_1::GnssSvInfo>& svInfoList) override {
-        return gnssSvStatusCbImpl(svInfoList);
+        return gnssSvStatusCbImpl<hidl_vec<IGnssCallback_V2_1::GnssSvInfo>,
+                                  IGnssCallback_V1_0::GnssSvInfo>(svInfoList);
     }
     Return<void> gnssSetCapabilitiesCb_2_1(uint32_t capabilities) override;
 
     // TODO: Reconsider allocation cost vs threadsafety on these statics
     static const char* sNmeaString;
     static size_t sNmeaStringLength;
+
+    template <class T>
+    static Return<void> gnssLocationCbImpl(const T& location);
+
+    template <class T_list, class T_sv_info>
+    static Return<void> gnssSvStatusCbImpl(const T_list& svStatus);
+
 private:
-    template<class T>
-    Return<void> gnssLocationCbImpl(const T& location);
-
-    template<class T>
-    Return<void> gnssSvStatusCbImpl(const T& svStatus);
-
-    template<class T>
-    uint32_t getHasBasebandCn0DbHzFlag(const T& svStatus) {
+    template <class T>
+    static uint32_t getHasBasebandCn0DbHzFlag(const T& svStatus) {
         return 0;
     }
 
-    template<class T>
-    double getBasebandCn0DbHz(const T& svStatus, size_t i) {
+    template <class T>
+    static double getBasebandCn0DbHz(const T& svStatus, size_t i) {
         return 0.0;
     }
 
-    uint32_t getGnssSvInfoListSize(const IGnssCallback_V1_0::GnssSvStatus& svStatus) {
-        return svStatus.numSvs;
-    }
-
-    uint32_t getGnssSvInfoListSize(const hidl_vec<IGnssCallback_V2_0::GnssSvInfo>& svInfoList) {
+    template <class T>
+    static uint32_t getGnssSvInfoListSize(const T& svInfoList) {
         return svInfoList.size();
     }
 
-    uint32_t getGnssSvInfoListSize(const hidl_vec<IGnssCallback_V2_1::GnssSvInfo>& svInfoList) {
-        return svInfoList.size();
+    static const IGnssCallbackAidl::GnssSvInfo& getGnssSvInfoOfIndex(
+            const std::vector<IGnssCallbackAidl::GnssSvInfo>& svInfoList, size_t i) {
+        return svInfoList[i];
     }
 
-    const IGnssCallback_V1_0::GnssSvInfo& getGnssSvInfoOfIndex(
+    static const IGnssCallback_V1_0::GnssSvInfo& getGnssSvInfoOfIndex(
             const IGnssCallback_V1_0::GnssSvStatus& svStatus, size_t i) {
         return svStatus.gnssSvList.data()[i];
     }
 
-    const IGnssCallback_V1_0::GnssSvInfo& getGnssSvInfoOfIndex(
+    static const IGnssCallback_V1_0::GnssSvInfo& getGnssSvInfoOfIndex(
             const hidl_vec<IGnssCallback_V2_0::GnssSvInfo>& svInfoList, size_t i) {
         return svInfoList[i].v1_0;
     }
 
-    const IGnssCallback_V1_0::GnssSvInfo& getGnssSvInfoOfIndex(
+    static const IGnssCallback_V1_0::GnssSvInfo& getGnssSvInfoOfIndex(
             const hidl_vec<IGnssCallback_V2_1::GnssSvInfo>& svInfoList, size_t i) {
         return svInfoList[i].v2_0.v1_0;
     }
 
-    uint32_t getConstellationType(const IGnssCallback_V1_0::GnssSvStatus& svStatus, size_t i) {
-        return static_cast<uint32_t>(svStatus.gnssSvList.data()[i].constellation);
-    }
-
-    uint32_t getConstellationType(const hidl_vec<IGnssCallback_V2_0::GnssSvInfo>& svInfoList, size_t i) {
+    template <class T>
+    static uint32_t getConstellationType(const T& svInfoList, size_t i) {
         return static_cast<uint32_t>(svInfoList[i].constellation);
     }
-
-    uint32_t getConstellationType(const hidl_vec<IGnssCallback_V2_1::GnssSvInfo>& svInfoList, size_t i) {
-        return static_cast<uint32_t>(svInfoList[i].v2_0.constellation);
-    }
 };
 
 Return<void> GnssCallback::gnssNameCb(const android::hardware::hidl_string& name) {
@@ -441,14 +471,43 @@
     return SVID_FLAGS_HAS_BASEBAND_CN0;
 }
 
+template <>
+uint32_t GnssCallback::getHasBasebandCn0DbHzFlag(
+        const std::vector<IGnssCallbackAidl::GnssSvInfo>& svStatus) {
+    return SVID_FLAGS_HAS_BASEBAND_CN0;
+}
+
+template <>
+double GnssCallback::getBasebandCn0DbHz(
+        const std::vector<IGnssCallbackAidl::GnssSvInfo>& svInfoList, size_t i) {
+    return svInfoList[i].basebandCN0DbHz;
+}
+
 template<>
 double GnssCallback::getBasebandCn0DbHz(const hidl_vec<IGnssCallback_V2_1::GnssSvInfo>& svInfoList,
         size_t i) {
     return svInfoList[i].basebandCN0DbHz;
 }
 
-template<class T>
-Return<void> GnssCallback::gnssSvStatusCbImpl(const T& svStatus) {
+template <>
+uint32_t GnssCallback::getGnssSvInfoListSize(const IGnssCallback_V1_0::GnssSvStatus& svStatus) {
+    return svStatus.numSvs;
+}
+
+template <>
+uint32_t GnssCallback::getConstellationType(const IGnssCallback_V1_0::GnssSvStatus& svStatus,
+                                            size_t i) {
+    return static_cast<uint32_t>(svStatus.gnssSvList.data()[i].constellation);
+}
+
+template <>
+uint32_t GnssCallback::getConstellationType(
+        const hidl_vec<IGnssCallback_V2_1::GnssSvInfo>& svInfoList, size_t i) {
+    return static_cast<uint32_t>(svInfoList[i].v2_0.constellation);
+}
+
+template <class T_list, class T_sv_info>
+Return<void> GnssCallback::gnssSvStatusCbImpl(const T_list& svStatus) {
     JNIEnv* env = getJniEnv();
 
     uint32_t listSize = getGnssSvInfoListSize(svStatus);
@@ -476,7 +535,7 @@
             CONSTELLATION_TYPE_SHIFT_WIDTH = 8
         };
 
-        const IGnssCallback_V1_0::GnssSvInfo& info = getGnssSvInfoOfIndex(svStatus, i);
+        const T_sv_info& info = getGnssSvInfoOfIndex(svStatus, i);
         svidWithFlags[i] = (info.svid << SVID_SHIFT_WIDTH) |
             (getConstellationType(svStatus, i) << CONSTELLATION_TYPE_SHIFT_WIDTH) |
             static_cast<uint32_t>(info.svFlag);
@@ -586,6 +645,16 @@
 class GnssCallbackAidl : public android::hardware::gnss::BnGnssCallback {
 public:
     Status gnssSetCapabilitiesCb(const int capabilities) override;
+    Status gnssStatusCb(const GnssStatusValue status) override;
+    Status gnssSvStatusCb(const std::vector<GnssSvInfo>& svInfoList) override;
+    Status gnssLocationCb(const GnssLocationAidl& location) override;
+    Status gnssNmeaCb(const int64_t timestamp, const std::string& nmea) override;
+    Status gnssAcquireWakelockCb() override;
+    Status gnssReleaseWakelockCb() override;
+    Status gnssSetSystemInfoCb(const GnssSystemInfo& info) override;
+    Status gnssRequestTimeCb() override;
+    Status gnssRequestLocationCb(const bool independentFromGnss,
+                                 const bool isUserEmergency) override;
 };
 
 Status GnssCallbackAidl::gnssSetCapabilitiesCb(const int capabilities) {
@@ -596,6 +665,76 @@
     return Status::ok();
 }
 
+Status GnssCallbackAidl::gnssStatusCb(const GnssStatusValue status) {
+    JNIEnv* env = getJniEnv();
+    env->CallVoidMethod(mCallbacksObj, method_reportStatus, status);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+    return Status::ok();
+}
+
+Status GnssCallbackAidl::gnssSvStatusCb(const std::vector<GnssSvInfo>& svInfoList) {
+    GnssCallback::gnssSvStatusCbImpl<std::vector<GnssSvInfo>, GnssSvInfo>(svInfoList);
+    return Status::ok();
+}
+
+Status GnssCallbackAidl::gnssLocationCb(const GnssLocationAidl& location) {
+    GnssCallback::gnssLocationCbImpl<GnssLocationAidl>(location);
+    return Status::ok();
+}
+
+Status GnssCallbackAidl::gnssNmeaCb(const int64_t timestamp, const std::string& nmea) {
+    JNIEnv* env = getJniEnv();
+    /*
+     * The Java code will call back to read these values.
+     * We do this to avoid creating unnecessary String objects.
+     */
+    GnssCallback::sNmeaString = nmea.c_str();
+    GnssCallback::sNmeaStringLength = nmea.size();
+
+    env->CallVoidMethod(mCallbacksObj, method_reportNmea, timestamp);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+    return Status::ok();
+}
+
+Status GnssCallbackAidl::gnssAcquireWakelockCb() {
+    acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME);
+    return Status::ok();
+}
+
+Status GnssCallbackAidl::gnssReleaseWakelockCb() {
+    release_wake_lock(WAKE_LOCK_NAME);
+    return Status::ok();
+}
+
+Status GnssCallbackAidl::gnssSetSystemInfoCb(const GnssSystemInfo& info) {
+    ALOGD("%s: yearOfHw=%d, name=%s\n", __func__, info.yearOfHw, info.name.c_str());
+    JNIEnv* env = getJniEnv();
+    env->CallVoidMethod(mCallbacksObj, method_setGnssYearOfHardware, info.yearOfHw);
+    jstring jstringName = env->NewStringUTF(info.name.c_str());
+    env->CallVoidMethod(mCallbacksObj, method_setGnssHardwareModelName, jstringName);
+    if (jstringName) {
+        env->DeleteLocalRef(jstringName);
+    }
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+    return Status::ok();
+}
+
+Status GnssCallbackAidl::gnssRequestTimeCb() {
+    JNIEnv* env = getJniEnv();
+    env->CallVoidMethod(mCallbacksObj, method_requestUtcTime);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+    return Status::ok();
+}
+
+Status GnssCallbackAidl::gnssRequestLocationCb(const bool independentFromGnss,
+                                               const bool isUserEmergency) {
+    JNIEnv* env = getJniEnv();
+    env->CallVoidMethod(mCallbacksObj, method_requestLocation, boolToJbool(independentFromGnss),
+                        boolToJbool(isUserEmergency));
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+    return Status::ok();
+}
+
 /*
  * GnssPowerIndicationCallback class implements the callback methods for the IGnssPowerIndication
  * interface.
@@ -797,7 +936,10 @@
 static void android_location_gnss_hal_GnssNative_set_gps_service_handle() {
     gnssHalAidl = waitForVintfService<IGnssAidl>();
     if (gnssHalAidl != nullptr) {
-        ALOGD("Successfully got GNSS AIDL handle.");
+        ALOGD("Successfully got GNSS AIDL handle. Version=%d.", gnssHalAidl->getInterfaceVersion());
+        if (gnssHalAidl->getInterfaceVersion() >= 2) {
+            return;
+        }
     }
 
     ALOGD("Trying IGnss_V2_1::getService()");
@@ -952,15 +1094,17 @@
 
     // TODO: linkToDeath for AIDL HAL
 
-    gnssHalDeathRecipient = new GnssDeathRecipient();
-    hardware::Return<bool> linked = gnssHal->linkToDeath(gnssHalDeathRecipient, /*cookie*/ 0);
-    if (!linked.isOk()) {
-        ALOGE("Transaction error in linking to GnssHAL death: %s",
-                linked.description().c_str());
-    } else if (!linked) {
-        ALOGW("Unable to link to GnssHal death notifications");
-    } else {
-        ALOGD("Link to death notification successful");
+    if (gnssHal != nullptr) {
+        gnssHalDeathRecipient = new GnssDeathRecipient();
+        hardware::Return<bool> linked = gnssHal->linkToDeath(gnssHalDeathRecipient, /*cookie*/ 0);
+        if (!linked.isOk()) {
+            ALOGE("Transaction error in linking to GnssHAL death: %s",
+                  linked.description().c_str());
+        } else if (!linked) {
+            ALOGW("Unable to link to GnssHal death notifications");
+        } else {
+            ALOGD("Link to death notification successful");
+        }
     }
 
     if (gnssHalAidl != nullptr) {
@@ -1104,22 +1248,24 @@
     // Allow all causal combinations between IGnss.hal and IGnssDebug.hal. That means,
     // 2.0@IGnss can be paired with {1.0, 2.0}@IGnssDebug
     // 1.0@IGnss is paired with 1.0@IGnssDebug
-    gnssDebugIface = nullptr;
-    if (gnssHal_V2_0 != nullptr) {
-        auto gnssDebug = gnssHal_V2_0->getExtensionGnssDebug_2_0();
-        if (!gnssDebug.isOk()) {
-            ALOGD("Unable to get a handle to GnssDebug_V2_0");
-        } else {
-            gnssDebugIface_V2_0 = gnssDebug;
-            gnssDebugIface = gnssDebugIface_V2_0;
+
+    if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+        sp<IGnssDebugAidl> gnssDebugAidl;
+        auto status = gnssHalAidl->getExtensionGnssDebug(&gnssDebugAidl);
+        if (checkAidlStatus(status, "Unable to get a handle to GnssDebug interface.")) {
+            gnssDebugIface = std::make_unique<gnss::GnssDebug>(gnssDebugAidl);
+        }
+    }
+    if (gnssHal_V2_0 != nullptr && gnssDebugIface == nullptr) {
+        auto gnssDebug_V2_0 = gnssHal_V2_0->getExtensionGnssDebug_2_0();
+        if (checkHidlReturn(gnssDebug_V2_0, "Unable to get a handle to GnssDebug_V2_0.")) {
+            gnssDebugIface = std::make_unique<gnss::GnssDebug_V2_0>(gnssDebug_V2_0);
         }
     }
     if (gnssHal != nullptr && gnssDebugIface == nullptr) {
-        auto gnssDebug = gnssHal->getExtensionGnssDebug();
-        if (!gnssDebug.isOk()) {
-            ALOGD("Unable to get a handle to GnssDebug");
-        } else {
-            gnssDebugIface = gnssDebug;
+        auto gnssDebug_V1_0 = gnssHal->getExtensionGnssDebug();
+        if (checkHidlReturn(gnssDebug_V1_0, "Unable to get a handle to GnssDebug_V1_0.")) {
+            gnssDebugIface = std::make_unique<gnss::GnssDebug_V1_0>(gnssDebug_V1_0);
         }
     }
 
@@ -1161,7 +1307,7 @@
             gnssConfigurationIface =
                     std::make_unique<gnss::GnssConfiguration_V1_1>(gnssConfiguration);
         }
-    } else {
+    } else if (gnssHal != nullptr) {
         auto gnssConfiguration = gnssHal->getExtensionGnssConfiguration();
         if (checkHidlReturn(gnssConfiguration,
                             "Unable to get a handle to GnssConfiguration_V1_0")) {
@@ -1227,7 +1373,7 @@
 }
 
 static jboolean android_location_gnss_hal_GnssNative_is_supported(JNIEnv* /* env */, jclass) {
-    return (gnssHal != nullptr) ?  JNI_TRUE : JNI_FALSE;
+    return (gnssHalAidl != nullptr || gnssHal != nullptr) ? JNI_TRUE : JNI_FALSE;
 }
 
 static jboolean android_location_GnssNetworkConnectivityHandler_is_agps_ril_supported(
@@ -1261,26 +1407,26 @@
         return JNI_FALSE;
     }
 
-    Return<bool> result = false;
-
     // Set top level IGnss.hal callback.
-    sp<IGnssCallback_V2_1> gnssCbIface = new GnssCallback();
-    if (gnssHal_V2_1 != nullptr) {
-        result = gnssHal_V2_1->setCallback_2_1(gnssCbIface);
-    } else if (gnssHal_V2_0 != nullptr) {
-        result = gnssHal_V2_0->setCallback_2_0(gnssCbIface);
-    } else if (gnssHal_V1_1 != nullptr) {
-        result = gnssHal_V1_1->setCallback_1_1(gnssCbIface);
-    } else if (gnssHal != nullptr) {
-        result = gnssHal->setCallback(gnssCbIface);
+    if (gnssHal != nullptr) {
+        Return<bool> result = false;
+        sp<IGnssCallback_V2_1> gnssCbIface = new GnssCallback();
+        if (gnssHal_V2_1 != nullptr) {
+            result = gnssHal_V2_1->setCallback_2_1(gnssCbIface);
+        } else if (gnssHal_V2_0 != nullptr) {
+            result = gnssHal_V2_0->setCallback_2_0(gnssCbIface);
+        } else if (gnssHal_V1_1 != nullptr) {
+            result = gnssHal_V1_1->setCallback_1_1(gnssCbIface);
+        } else {
+            result = gnssHal->setCallback(gnssCbIface);
+        }
+        if (!checkHidlReturn(result, "IGnss setCallback() failed.")) {
+            return JNI_FALSE;
+        }
     }
 
-    if (!checkHidlReturn(result, "IGnss setCallback() failed.")) {
-        return JNI_FALSE;
-    }
-
-    sp<IGnssCallbackAidl> gnssCbIfaceAidl = new GnssCallbackAidl();
     if (gnssHalAidl != nullptr) {
+        sp<IGnssCallbackAidl> gnssCbIfaceAidl = new GnssCallbackAidl();
         auto status = gnssHalAidl->setCallback(gnssCbIfaceAidl);
         if (!checkAidlStatus(status, "IGnssAidl setCallback() failed.")) {
             return JNI_FALSE;
@@ -1296,7 +1442,7 @@
         }
     } else if (gnssXtraIface != nullptr) {
         sp<IGnssXtraCallback> gnssXtraCbIface = new GnssXtraCallback();
-        result = gnssXtraIface->setCallback(gnssXtraCbIface);
+        auto result = gnssXtraIface->setCallback(gnssXtraCbIface);
         if (!checkHidlReturn(result, "IGnssXtra setCallback() failed.")) {
             gnssXtraIface = nullptr;
         } else {
@@ -1339,20 +1485,20 @@
     if (gnssVisibilityControlIface != nullptr) {
         sp<IGnssVisibilityControlCallback> gnssVisibilityControlCbIface =
                 new GnssVisibilityControlCallback();
-        result = gnssVisibilityControlIface->setCallback(gnssVisibilityControlCbIface);
+        auto result = gnssVisibilityControlIface->setCallback(gnssVisibilityControlCbIface);
         checkHidlReturn(result, "IGnssVisibilityControl setCallback() failed.");
     }
 
     // Set IMeasurementCorrections.hal callback.
     if (gnssCorrectionsIface_V1_1 != nullptr) {
-            sp<IMeasurementCorrectionsCallback> gnssCorrectionsIfaceCbIface =
-                    new MeasurementCorrectionsCallback();
-            result = gnssCorrectionsIface_V1_1->setCallback(gnssCorrectionsIfaceCbIface);
-            checkHidlReturn(result, "IMeasurementCorrections 1.1 setCallback() failed.");
+        sp<IMeasurementCorrectionsCallback> gnssCorrectionsIfaceCbIface =
+                new MeasurementCorrectionsCallback();
+        auto result = gnssCorrectionsIface_V1_1->setCallback(gnssCorrectionsIfaceCbIface);
+        checkHidlReturn(result, "IMeasurementCorrections 1.1 setCallback() failed.");
     } else if (gnssCorrectionsIface_V1_0 != nullptr) {
         sp<IMeasurementCorrectionsCallback> gnssCorrectionsIfaceCbIface =
                 new MeasurementCorrectionsCallback();
-        result = gnssCorrectionsIface_V1_0->setCallback(gnssCorrectionsIfaceCbIface);
+        auto result = gnssCorrectionsIface_V1_0->setCallback(gnssCorrectionsIfaceCbIface);
         checkHidlReturn(result, "IMeasurementCorrections 1.0 setCallback() failed.");
     } else {
         ALOGI("Unable to find IMeasurementCorrections.");
@@ -1386,6 +1532,15 @@
 static jboolean android_location_gnss_hal_GnssNative_set_position_mode(
         JNIEnv* /* env */, jclass, jint mode, jint recurrence, jint min_interval,
         jint preferred_accuracy, jint preferred_time, jboolean low_power_mode) {
+    if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+        auto status = gnssHalAidl->setPositionMode(static_cast<IGnssAidl::GnssPositionMode>(mode),
+                                                   static_cast<IGnssAidl::GnssPositionRecurrence>(
+                                                           recurrence),
+                                                   min_interval, preferred_accuracy, preferred_time,
+                                                   low_power_mode);
+        return checkAidlStatus(status, "IGnssAidl setPositionMode() failed.");
+    }
+
     Return<bool> result = false;
     if (gnssHal_V1_1 != nullptr) {
          result = gnssHal_V1_1->setPositionMode_1_1(static_cast<IGnss_V1_0::GnssPositionMode>(mode),
@@ -1406,6 +1561,11 @@
 }
 
 static jboolean android_location_gnss_hal_GnssNative_start(JNIEnv* /* env */, jclass) {
+    if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+        auto status = gnssHalAidl->start();
+        return checkAidlStatus(status, "IGnssAidl start() failed.");
+    }
+
     if (gnssHal == nullptr) {
         return JNI_FALSE;
     }
@@ -1415,6 +1575,11 @@
 }
 
 static jboolean android_location_gnss_hal_GnssNative_stop(JNIEnv* /* env */, jclass) {
+    if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+        auto status = gnssHalAidl->stop();
+        return checkAidlStatus(status, "IGnssAidl stop() failed.");
+    }
+
     if (gnssHal == nullptr) {
         return JNI_FALSE;
     }
@@ -1425,6 +1590,12 @@
 
 static void android_location_gnss_hal_GnssNative_delete_aiding_data(JNIEnv* /* env */, jclass,
                                                                     jint flags) {
+    if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+        auto status = gnssHalAidl->deleteAidingData(static_cast<IGnssAidl::GnssAidingData>(flags));
+        checkAidlStatus(status, "IGnssAidl deleteAidingData() failed.");
+        return;
+    }
+
     if (gnssHal == nullptr) {
         return;
     }
@@ -1488,10 +1659,15 @@
 static void android_location_gnss_hal_GnssNative_inject_time(JNIEnv* /* env */, jclass, jlong time,
                                                              jlong timeReference,
                                                              jint uncertainty) {
-    if (gnssHal == nullptr) {
+    if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+        auto status = gnssHalAidl->injectTime(time, timeReference, uncertainty);
+        checkAidlStatus(status, "IGnssAidl injectTime() failed.");
         return;
     }
 
+    if (gnssHal == nullptr) {
+        return;
+    }
     auto result = gnssHal->injectTime(time, timeReference, uncertainty);
     checkHidlReturn(result, "IGnss injectTime() failed.");
 }
@@ -1503,6 +1679,19 @@
         jfloat speedAccuracyMetersPerSecond, jfloat bearingAccuracyDegrees, jlong timestamp,
         jint elapsedRealtimeFlags, jlong elapsedRealtimeNanos,
         jdouble elapsedRealtimeUncertaintyNanos) {
+    if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+        GnssLocationAidl location =
+                createGnssLocation(gnssLocationFlags, latitudeDegrees, longitudeDegrees,
+                                   altitudeMeters, speedMetersPerSec, bearingDegrees,
+                                   horizontalAccuracyMeters, verticalAccuracyMeters,
+                                   speedAccuracyMetersPerSecond, bearingAccuracyDegrees, timestamp,
+                                   elapsedRealtimeFlags, elapsedRealtimeNanos,
+                                   elapsedRealtimeUncertaintyNanos);
+        auto status = gnssHalAidl->injectBestLocation(location);
+        checkAidlStatus(status, "IGnssAidl injectBestLocation() failed.");
+        return;
+    }
+
     if (gnssHal_V2_0 != nullptr) {
         GnssLocation_V2_0 location = createGnssLocation_V2_0(
                 gnssLocationFlags,
@@ -1544,15 +1733,31 @@
     ALOGE("IGnss injectBestLocation() is called but gnssHal_V1_1 is not available.");
 }
 
-static void android_location_gnss_hal_GnssNative_inject_location(JNIEnv* /* env */, jclass,
-                                                                 jdouble latitude,
-                                                                 jdouble longitude,
-                                                                 jfloat accuracy) {
-    if (gnssHal == nullptr) {
+static void android_location_gnss_hal_GnssNative_inject_location(
+        JNIEnv* /* env */, jclass, jint gnssLocationFlags, jdouble latitudeDegrees,
+        jdouble longitudeDegrees, jdouble altitudeMeters, jfloat speedMetersPerSec,
+        jfloat bearingDegrees, jfloat horizontalAccuracyMeters, jfloat verticalAccuracyMeters,
+        jfloat speedAccuracyMetersPerSecond, jfloat bearingAccuracyDegrees, jlong timestamp,
+        jint elapsedRealtimeFlags, jlong elapsedRealtimeNanos,
+        jdouble elapsedRealtimeUncertaintyNanos) {
+    if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+        GnssLocationAidl location =
+                createGnssLocation(gnssLocationFlags, latitudeDegrees, longitudeDegrees,
+                                   altitudeMeters, speedMetersPerSec, bearingDegrees,
+                                   horizontalAccuracyMeters, verticalAccuracyMeters,
+                                   speedAccuracyMetersPerSecond, bearingAccuracyDegrees, timestamp,
+                                   elapsedRealtimeFlags, elapsedRealtimeNanos,
+                                   elapsedRealtimeUncertaintyNanos);
+        auto status = gnssHalAidl->injectLocation(location);
+        checkAidlStatus(status, "IGnssAidl injectLocation() failed.");
         return;
     }
 
-    auto result = gnssHal->injectLocation(latitude, longitude, accuracy);
+    if (gnssHal == nullptr) {
+        return;
+    }
+    auto result =
+            gnssHal->injectLocation(latitudeDegrees, longitudeDegrees, horizontalAccuracyMeters);
     checkHidlReturn(result, "IGnss injectLocation() failed.");
 }
 
@@ -1639,108 +1844,16 @@
     checkHidlReturn(result, "IGnssNi respond() failed.");
 }
 
-const IGnssDebug_V1_0::SatelliteData& getSatelliteData(
-        const hidl_vec<IGnssDebug_V1_0::SatelliteData>& satelliteDataArray, size_t i) {
-    return satelliteDataArray[i];
-}
-
-const IGnssDebug_V1_0::SatelliteData& getSatelliteData(
-        const hidl_vec<IGnssDebug_V2_0::SatelliteData>& satelliteDataArray, size_t i) {
-    return satelliteDataArray[i].v1_0;
-}
-
-template<class T>
-uint32_t getConstellationType(const hidl_vec<T>& satelliteDataArray, size_t i) {
-    return static_cast<uint32_t>(satelliteDataArray[i].constellation);
-}
-
-template<class T>
-static jstring parseDebugData(JNIEnv* env, std::stringstream& internalState, const T& data) {
-    internalState << "Gnss Location Data:: ";
-    if (!data.position.valid) {
-        internalState << "not valid";
-    } else {
-        internalState << "LatitudeDegrees: " << data.position.latitudeDegrees
-                      << ", LongitudeDegrees: " << data.position.longitudeDegrees
-                      << ", altitudeMeters: " << data.position.altitudeMeters
-                      << ", speedMetersPerSecond: " << data.position.speedMetersPerSec
-                      << ", bearingDegrees: " << data.position.bearingDegrees
-                      << ", horizontalAccuracyMeters: "
-                      << data.position.horizontalAccuracyMeters
-                      << ", verticalAccuracyMeters: " << data.position.verticalAccuracyMeters
-                      << ", speedAccuracyMetersPerSecond: "
-                      << data.position.speedAccuracyMetersPerSecond
-                      << ", bearingAccuracyDegrees: " << data.position.bearingAccuracyDegrees
-                      << ", ageSeconds: " << data.position.ageSeconds;
-    }
-    internalState << std::endl;
-
-    internalState << "Gnss Time Data:: timeEstimate: " << data.time.timeEstimate
-                  << ", timeUncertaintyNs: " << data.time.timeUncertaintyNs
-                  << ", frequencyUncertaintyNsPerSec: "
-                  << data.time.frequencyUncertaintyNsPerSec << std::endl;
-
-    if (data.satelliteDataArray.size() != 0) {
-        internalState << "Satellite Data for " << data.satelliteDataArray.size()
-                      << " satellites:: " << std::endl;
-    }
-
-    internalState << "constell: 1=GPS, 2=SBAS, 3=GLO, 4=QZSS, 5=BDS, 6=GAL, 7=IRNSS; "
-                  << "ephType: 0=Eph, 1=Alm, 2=Unk; "
-                  << "ephSource: 0=Demod, 1=Supl, 2=Server, 3=Unk; "
-                  << "ephHealth: 0=Good, 1=Bad, 2=Unk" << std::endl;
-    for (size_t i = 0; i < data.satelliteDataArray.size(); i++) {
-        IGnssDebug_V1_0::SatelliteData satelliteData =
-                getSatelliteData(data.satelliteDataArray, i);
-        internalState << "constell: "
-                      << getConstellationType(data.satelliteDataArray, i)
-                      << ", svid: " << std::setw(3) << satelliteData.svid
-                      << ", serverPredAvail: "
-                      << satelliteData.serverPredictionIsAvailable
-                      << ", serverPredAgeSec: " << std::setw(7)
-                      << satelliteData.serverPredictionAgeSeconds
-                      << ", ephType: "
-                      << static_cast<uint32_t>(satelliteData.ephemerisType)
-                      << ", ephSource: "
-                      << static_cast<uint32_t>(satelliteData.ephemerisSource)
-                      << ", ephHealth: "
-                      << static_cast<uint32_t>(satelliteData.ephemerisHealth)
-                      << ", ephAgeSec: " << std::setw(7)
-                      << satelliteData.ephemerisAgeSeconds << std::endl;
-    }
-    return (jstring) env->NewStringUTF(internalState.str().c_str());
-}
-
 static jstring android_location_gnss_hal_GnssNative_get_internal_state(JNIEnv* env, jclass) {
-    jstring internalStateStr = nullptr;
     /*
      * TODO: Create a jobject to represent GnssDebug.
      */
 
-    std::stringstream internalState;
-
     if (gnssDebugIface == nullptr) {
         ALOGE("%s: IGnssDebug interface not available.", __func__);
-    } else if (gnssDebugIface_V2_0 != nullptr) {
-        IGnssDebug_V2_0::DebugData data;
-        auto result = gnssDebugIface_V2_0->getDebugData_2_0(
-                [&data](const IGnssDebug_V2_0::DebugData& debugData) {
-                    data = debugData;
-                });
-        if (checkHidlReturn(result, "IGnssDebug getDebugData_2_0() failed.")) {
-            internalStateStr = parseDebugData(env, internalState, data);
-        }
-    } else {
-        IGnssDebug_V1_0::DebugData data;
-        auto result = gnssDebugIface->getDebugData(
-                [&data](const IGnssDebug_V1_0::DebugData& debugData) {
-                    data = debugData;
-                });
-        if (checkHidlReturn(result, "IGnssDebug getDebugData() failed.")) {
-            internalStateStr = parseDebugData(env, internalState, data);
-        }
+        return nullptr;
     }
-    return internalStateStr;
+    return gnssDebugIface->getDebugData(env);
 }
 
 static void android_location_gnss_hal_GnssNative_request_power_stats(JNIEnv* env) {
@@ -1896,15 +2009,20 @@
 }
 
 static jboolean android_location_gnss_hal_GnssNative_start_measurement_collection(
-        JNIEnv* /* env */, jclass, jboolean enableFullTracking, jboolean enableCorrVecOutputs) {
+        JNIEnv* /* env */, jclass, jboolean enableFullTracking, jboolean enableCorrVecOutputs,
+        jint intervalMs) {
     if (gnssMeasurementIface == nullptr) {
         ALOGE("%s: IGnssMeasurement interface not available.", __func__);
         return JNI_FALSE;
     }
+    hardware::gnss::IGnssMeasurementInterface::Options options;
+    options.enableFullTracking = enableFullTracking;
+    options.enableCorrVecOutputs = enableCorrVecOutputs;
+    options.intervalMs = intervalMs;
 
     return gnssMeasurementIface->setCallback(std::make_unique<gnss::GnssMeasurementCallback>(
                                                      mCallbacksObj),
-                                             enableFullTracking, enableCorrVecOutputs);
+                                             options);
 }
 
 static jboolean android_location_gnss_hal_GnssNative_stop_measurement_collection(JNIEnv* env,
@@ -2292,7 +2410,7 @@
          reinterpret_cast<void*>(android_location_gnss_hal_GnssNative_inject_time)},
         {"native_inject_best_location", "(IDDDFFFFFFJIJD)V",
          reinterpret_cast<void*>(android_location_gnss_hal_GnssNative_inject_best_location)},
-        {"native_inject_location", "(DDF)V",
+        {"native_inject_location", "(IDDDFFFFFFJIJD)V",
          reinterpret_cast<void*>(android_location_gnss_hal_GnssNative_inject_location)},
         {"native_supports_psds", "()Z",
          reinterpret_cast<void*>(android_location_gnss_hal_GnssNative_supports_psds)},
@@ -2359,7 +2477,7 @@
         /* name, signature, funcPtr */
         {"native_is_measurement_supported", "()Z",
          reinterpret_cast<void*>(android_location_gnss_hal_GnssNative_is_measurement_supported)},
-        {"native_start_measurement_collection", "(ZZ)Z",
+        {"native_start_measurement_collection", "(ZZI)Z",
          reinterpret_cast<void*>(
                  android_location_gnss_hal_GnssNative_start_measurement_collection)},
         {"native_stop_measurement_collection", "()Z",
diff --git a/services/core/jni/gnss/AGnss.cpp b/services/core/jni/gnss/AGnss.cpp
index 00403d6..091fffd 100644
--- a/services/core/jni/gnss/AGnss.cpp
+++ b/services/core/jni/gnss/AGnss.cpp
@@ -43,7 +43,7 @@
 
 jboolean AGnss::dataConnOpen(JNIEnv* env, jlong networkHandle, jstring apn, jint apnIpType) {
     ScopedJniString jniApn{env, apn};
-    auto status = mIAGnss->dataConnOpen(networkHandle, String16(jniApn.c_str()),
+    auto status = mIAGnss->dataConnOpen(networkHandle, std::string(jniApn.c_str()),
                                         static_cast<IAGnss::ApnIpType>(apnIpType));
     return checkAidlStatus(status,
                            "IAGnssAidl dataConnOpen() failed. APN and its IP type not set.");
@@ -61,8 +61,8 @@
 
 jboolean AGnss::setServer(JNIEnv* env, jint type, jstring hostname, jint port) {
     ScopedJniString jniHostName{env, hostname};
-    auto status =
-            mIAGnss->setServer(static_cast<AGnssType>(type), String16(jniHostName.c_str()), port);
+    auto status = mIAGnss->setServer(static_cast<AGnssType>(type), std::string(jniHostName.c_str()),
+                                     port);
     return checkAidlStatus(status, "IAGnssAidl setServer() failed. Host name and port not set.");
 }
 
diff --git a/services/core/jni/gnss/Android.bp b/services/core/jni/gnss/Android.bp
index e49e81c..63f5f52 100644
--- a/services/core/jni/gnss/Android.bp
+++ b/services/core/jni/gnss/Android.bp
@@ -29,6 +29,7 @@
         "GnssBatching.cpp",
         "GnssBatchingCallback.cpp",
         "GnssConfiguration.cpp",
+        "GnssDebug.cpp",
         "GnssGeofence.cpp",
         "GnssGeofenceCallback.cpp",
         "GnssMeasurement.cpp",
diff --git a/services/core/jni/gnss/GnssDebug.cpp b/services/core/jni/gnss/GnssDebug.cpp
new file mode 100644
index 0000000..da53317
--- /dev/null
+++ b/services/core/jni/gnss/GnssDebug.cpp
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 before <log/log.h> to overwrite the default value.
+#define LOG_TAG "GnssDebugJni"
+
+#include "GnssDebug.h"
+
+#include "Utils.h"
+
+using android::hardware::gnss::IGnssDebug;
+using IGnssDebug_V1_0 = android::hardware::gnss::V1_0::IGnssDebug;
+using IGnssDebug_V2_0 = android::hardware::gnss::V2_0::IGnssDebug;
+
+namespace android::gnss {
+
+// Implementation of GnssDebug (AIDL HAL)
+
+GnssDebug::GnssDebug(const sp<IGnssDebug>& iGnssDebug) : mIGnssDebug(iGnssDebug) {
+    assert(mIGnssDebug != nullptr);
+}
+
+jstring GnssDebug::getDebugData(JNIEnv* env) {
+    std::stringstream internalState;
+    IGnssDebug::DebugData data;
+    auto status = mIGnssDebug->getDebugData(&data);
+    if (checkAidlStatus(status, "IGnssDebug getDebugData() failed.")) {
+        return GnssDebugUtil::parseDebugData<IGnssDebug::DebugData,
+                                             IGnssDebug::SatelliteData>(env, internalState, data);
+    }
+    return nullptr;
+}
+
+// Implementation of GnssDebug_V1_0
+
+GnssDebug_V1_0::GnssDebug_V1_0(const sp<IGnssDebug_V1_0>& iGnssDebug)
+      : mIGnssDebug_V1_0(iGnssDebug) {
+    assert(mIGnssDebug_V1_0 != nullptr);
+}
+
+jstring GnssDebug_V1_0::getDebugData(JNIEnv* env) {
+    std::stringstream internalState;
+    IGnssDebug_V1_0::DebugData data;
+    auto result = mIGnssDebug_V1_0->getDebugData(
+            [&data](const IGnssDebug_V1_0::DebugData& debugData) { data = debugData; });
+    if (checkHidlReturn(result, "IGnssDebug getDebugData_1_0() failed.")) {
+        return GnssDebugUtil::parseDebugData<IGnssDebug_V1_0::DebugData,
+                                             IGnssDebug_V1_0::SatelliteData>(env, internalState,
+                                                                             data);
+    }
+    return nullptr;
+}
+
+// Implementation of GnssDebug_V2_0
+
+GnssDebug_V2_0::GnssDebug_V2_0(const sp<IGnssDebug_V2_0>& iGnssDebug)
+      : mIGnssDebug_V2_0{iGnssDebug} {
+    assert(mIGnssDebug_V2_0 != nullptr);
+}
+
+jstring GnssDebug_V2_0::getDebugData(JNIEnv* env) {
+    std::stringstream internalState;
+    IGnssDebug_V2_0::DebugData data;
+    auto result = mIGnssDebug_V2_0->getDebugData_2_0(
+            [&data](const IGnssDebug_V2_0::DebugData& debugData) { data = debugData; });
+    if (checkHidlReturn(result, "IGnssDebug getDebugData_2_0() failed.")) {
+        return GnssDebugUtil::parseDebugData<IGnssDebug_V2_0::DebugData,
+                                             IGnssDebug_V1_0::SatelliteData>(env, internalState,
+                                                                             data);
+    }
+    return nullptr;
+}
+
+const android::hardware::gnss::V1_0::IGnssDebug::SatelliteData& GnssDebugUtil::getSatelliteData(
+        const hardware::hidl_vec<android::hardware::gnss::V1_0::IGnssDebug::SatelliteData>&
+                satelliteDataArray,
+        size_t i) {
+    return satelliteDataArray[i];
+}
+
+const android::hardware::gnss::V1_0::IGnssDebug::SatelliteData& GnssDebugUtil::getSatelliteData(
+        const hardware::hidl_vec<android::hardware::gnss::V2_0::IGnssDebug::SatelliteData>&
+                satelliteDataArray,
+        size_t i) {
+    return satelliteDataArray[i].v1_0;
+}
+
+const android::hardware::gnss::IGnssDebug::SatelliteData& GnssDebugUtil::getSatelliteData(
+        const std::vector<android::hardware::gnss::IGnssDebug::SatelliteData>& satelliteDataArray,
+        size_t i) {
+    return satelliteDataArray[i];
+}
+
+} // namespace android::gnss
diff --git a/services/core/jni/gnss/GnssDebug.h b/services/core/jni/gnss/GnssDebug.h
new file mode 100644
index 0000000..9f5ff21
--- /dev/null
+++ b/services/core/jni/gnss/GnssDebug.h
@@ -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.
+ */
+
+#ifndef _ANDROID_SERVER_GNSS_GNSSDEBUG_H
+#define _ANDROID_SERVER_GNSS_GNSSDEBUG_H
+
+#pragma once
+
+#ifndef LOG_TAG
+#error LOG_TAG must be defined before including this file.
+#endif
+
+#include <android/hardware/gnss/1.0/IGnssDebug.h>
+#include <android/hardware/gnss/2.0/IGnssDebug.h>
+#include <android/hardware/gnss/BnGnssDebug.h>
+#include <log/log.h>
+
+#include <iomanip>
+
+#include "jni.h"
+
+namespace android::gnss {
+
+class GnssDebugInterface {
+public:
+    virtual ~GnssDebugInterface() {}
+    virtual jstring getDebugData(JNIEnv* env) = 0;
+};
+
+class GnssDebug : public GnssDebugInterface {
+public:
+    GnssDebug(const sp<android::hardware::gnss::IGnssDebug>& iGnssDebug);
+    jstring getDebugData(JNIEnv* env) override;
+
+private:
+    const sp<android::hardware::gnss::IGnssDebug> mIGnssDebug;
+};
+
+class GnssDebug_V1_0 : public GnssDebugInterface {
+public:
+    GnssDebug_V1_0(const sp<android::hardware::gnss::V1_0::IGnssDebug>& iGnssDebug);
+    jstring getDebugData(JNIEnv* env) override;
+
+private:
+    const sp<android::hardware::gnss::V1_0::IGnssDebug> mIGnssDebug_V1_0;
+};
+
+class GnssDebug_V2_0 : public GnssDebugInterface {
+public:
+    GnssDebug_V2_0(const sp<android::hardware::gnss::V2_0::IGnssDebug>& iGnssDebug);
+    jstring getDebugData(JNIEnv* env) override;
+
+private:
+    const sp<android::hardware::gnss::V2_0::IGnssDebug> mIGnssDebug_V2_0;
+};
+
+struct GnssDebugUtil {
+    template <class T>
+    static uint32_t getConstellationType(const hardware::hidl_vec<T>& satelliteDataArray, size_t i);
+
+    template <class T>
+    static uint32_t getConstellationType(const std::vector<T>& satelliteDataArray, size_t i);
+
+    template <class T>
+    static uint32_t getTimeEstimateMs(const T& data);
+
+    template <class T_DebugData, class T_SatelliteData>
+    static jstring parseDebugData(JNIEnv* env, std::stringstream& internalState,
+                                  const T_DebugData& data);
+
+    const static android::hardware::gnss::V1_0::IGnssDebug::SatelliteData& getSatelliteData(
+            const hardware::hidl_vec<android::hardware::gnss::V1_0::IGnssDebug::SatelliteData>&
+                    satelliteDataArray,
+            size_t i);
+
+    const static android::hardware::gnss::V1_0::IGnssDebug::SatelliteData& getSatelliteData(
+            const hardware::hidl_vec<android::hardware::gnss::V2_0::IGnssDebug::SatelliteData>&
+                    satelliteDataArray,
+            size_t i);
+
+    const static android::hardware::gnss::IGnssDebug::SatelliteData& getSatelliteData(
+            const std::vector<android::hardware::gnss::IGnssDebug::SatelliteData>&
+                    satelliteDataArray,
+            size_t i);
+};
+
+template <class T>
+uint32_t GnssDebugUtil::getConstellationType(const hardware::hidl_vec<T>& satelliteDataArray,
+                                             size_t i) {
+    return static_cast<uint32_t>(satelliteDataArray[i].constellation);
+}
+
+template <class T>
+uint32_t GnssDebugUtil::getConstellationType(const std::vector<T>& satelliteDataArray, size_t i) {
+    return static_cast<uint32_t>(satelliteDataArray[i].constellation);
+}
+
+template <class T>
+uint32_t GnssDebugUtil::getTimeEstimateMs(const T& data) {
+    return data.time.timeEstimate;
+}
+
+template <>
+uint32_t GnssDebugUtil::getTimeEstimateMs(
+        const android::hardware::gnss::IGnssDebug::DebugData& data) {
+    return data.time.timeEstimateMs;
+}
+
+template <class T_DebugData, class T_SatelliteData>
+jstring GnssDebugUtil::parseDebugData(JNIEnv* env, std::stringstream& internalState,
+                                      const T_DebugData& data) {
+    internalState << "Gnss Location Data:: ";
+    if (!data.position.valid) {
+        internalState << "not valid";
+    } else {
+        internalState << "LatitudeDegrees: " << data.position.latitudeDegrees
+                      << ", LongitudeDegrees: " << data.position.longitudeDegrees
+                      << ", altitudeMeters: " << data.position.altitudeMeters
+                      << ", speedMetersPerSecond: " << data.position.speedMetersPerSec
+                      << ", bearingDegrees: " << data.position.bearingDegrees
+                      << ", horizontalAccuracyMeters: " << data.position.horizontalAccuracyMeters
+                      << ", verticalAccuracyMeters: " << data.position.verticalAccuracyMeters
+                      << ", speedAccuracyMetersPerSecond: "
+                      << data.position.speedAccuracyMetersPerSecond
+                      << ", bearingAccuracyDegrees: " << data.position.bearingAccuracyDegrees
+                      << ", ageSeconds: " << data.position.ageSeconds;
+    }
+    internalState << std::endl;
+
+    internalState << "Gnss Time Data:: timeEstimate: " << GnssDebugUtil::getTimeEstimateMs(data)
+                  << ", timeUncertaintyNs: " << data.time.timeUncertaintyNs
+                  << ", frequencyUncertaintyNsPerSec: " << data.time.frequencyUncertaintyNsPerSec
+                  << std::endl;
+
+    if (data.satelliteDataArray.size() != 0) {
+        internalState << "Satellite Data for " << data.satelliteDataArray.size()
+                      << " satellites:: " << std::endl;
+    }
+
+    internalState << "constell: 1=GPS, 2=SBAS, 3=GLO, 4=QZSS, 5=BDS, 6=GAL, 7=IRNSS; "
+                  << "ephType: 0=Eph, 1=Alm, 2=Unk; "
+                  << "ephSource: 0=Demod, 1=Supl, 2=Server, 3=Unk; "
+                  << "ephHealth: 0=Good, 1=Bad, 2=Unk" << std::endl;
+    for (size_t i = 0; i < data.satelliteDataArray.size(); i++) {
+        T_SatelliteData satelliteData = getSatelliteData(data.satelliteDataArray, i);
+        internalState << "constell: "
+                      << GnssDebugUtil::getConstellationType(data.satelliteDataArray, i)
+                      << ", svid: " << std::setw(3) << satelliteData.svid
+                      << ", serverPredAvail: " << satelliteData.serverPredictionIsAvailable
+                      << ", serverPredAgeSec: " << std::setw(7)
+                      << satelliteData.serverPredictionAgeSeconds
+                      << ", ephType: " << static_cast<uint32_t>(satelliteData.ephemerisType)
+                      << ", ephSource: " << static_cast<uint32_t>(satelliteData.ephemerisSource)
+                      << ", ephHealth: " << static_cast<uint32_t>(satelliteData.ephemerisHealth)
+                      << ", ephAgeSec: " << std::setw(7) << satelliteData.ephemerisAgeSeconds
+                      << std::endl;
+    }
+    return (jstring)env->NewStringUTF(internalState.str().c_str());
+}
+
+} // namespace android::gnss
+
+#endif // _ANDROID_SERVER_GNSS_GNSSDEBUG_H
diff --git a/services/core/jni/gnss/GnssMeasurement.cpp b/services/core/jni/gnss/GnssMeasurement.cpp
index 663d839..9fbf259 100644
--- a/services/core/jni/gnss/GnssMeasurement.cpp
+++ b/services/core/jni/gnss/GnssMeasurement.cpp
@@ -50,9 +50,15 @@
       : mIGnssMeasurement(iGnssMeasurement) {}
 
 jboolean GnssMeasurement::setCallback(const std::unique_ptr<GnssMeasurementCallback>& callback,
-                                      bool enableFullTracking, bool enableCorrVecOutputs) {
-    auto status = mIGnssMeasurement->setCallback(callback->getAidl(), enableFullTracking,
-                                                 enableCorrVecOutputs);
+                                      const IGnssMeasurementInterface::Options& options) {
+    if (mIGnssMeasurement->getInterfaceVersion() >= 2) {
+        auto status = mIGnssMeasurement->setCallbackWithOptions(callback->getAidl(), options);
+        if (checkAidlStatus(status, "IGnssMeasurement setCallbackWithOptions() failed.")) {
+            return true;
+        }
+    }
+    auto status = mIGnssMeasurement->setCallback(callback->getAidl(), options.enableFullTracking,
+                                                 options.enableCorrVecOutputs);
     return checkAidlStatus(status, "IGnssMeasurement setCallback() failed.");
 }
 
@@ -67,13 +73,16 @@
       : mIGnssMeasurement_V1_0(iGnssMeasurement) {}
 
 jboolean GnssMeasurement_V1_0::setCallback(const std::unique_ptr<GnssMeasurementCallback>& callback,
-                                           bool enableFullTracking, bool enableCorrVecOutputs) {
-    if (enableFullTracking == true) {
+                                           const IGnssMeasurementInterface::Options& options) {
+    if (options.enableFullTracking == true) {
         ALOGW("Full tracking mode is not supported in 1.0 GNSS HAL.");
     }
-    if (enableCorrVecOutputs == true) {
+    if (options.enableCorrVecOutputs == true) {
         ALOGW("Correlation vector output is not supported in 1.0 GNSS HAL.");
     }
+    if (options.intervalMs > 1000) {
+        ALOGW("Measurement interval is not supported in 1.0 GNSS HAL.");
+    }
     auto status = mIGnssMeasurement_V1_0->setCallback(callback->getHidl());
     if (!checkHidlReturn(status, "IGnssMeasurement setCallback() failed.")) {
         return JNI_FALSE;
@@ -93,11 +102,15 @@
       : GnssMeasurement_V1_0{iGnssMeasurement}, mIGnssMeasurement_V1_1(iGnssMeasurement) {}
 
 jboolean GnssMeasurement_V1_1::setCallback(const std::unique_ptr<GnssMeasurementCallback>& callback,
-                                           bool enableFullTracking, bool enableCorrVecOutputs) {
-    if (enableCorrVecOutputs == true) {
+                                           const IGnssMeasurementInterface::Options& options) {
+    if (options.enableCorrVecOutputs == true) {
         ALOGW("Correlation vector output is not supported in 1.1 GNSS HAL.");
     }
-    auto status = mIGnssMeasurement_V1_1->setCallback_1_1(callback->getHidl(), enableFullTracking);
+    if (options.intervalMs > 1000) {
+        ALOGW("Measurement interval is not supported in 1.0 GNSS HAL.");
+    }
+    auto status = mIGnssMeasurement_V1_1->setCallback_1_1(callback->getHidl(),
+                                                          options.enableFullTracking);
     if (!checkHidlReturn(status, "IGnssMeasurement setCallback_V1_1() failed.")) {
         return JNI_FALSE;
     }
@@ -111,11 +124,15 @@
       : GnssMeasurement_V1_1{iGnssMeasurement}, mIGnssMeasurement_V2_0(iGnssMeasurement) {}
 
 jboolean GnssMeasurement_V2_0::setCallback(const std::unique_ptr<GnssMeasurementCallback>& callback,
-                                           bool enableFullTracking, bool enableCorrVecOutputs) {
-    if (enableCorrVecOutputs == true) {
+                                           const IGnssMeasurementInterface::Options& options) {
+    if (options.enableCorrVecOutputs == true) {
         ALOGW("Correlation vector output is not supported in 2.0 GNSS HAL.");
     }
-    auto status = mIGnssMeasurement_V2_0->setCallback_2_0(callback->getHidl(), enableFullTracking);
+    if (options.intervalMs > 1000) {
+        ALOGW("Measurement interval is not supported in 1.0 GNSS HAL.");
+    }
+    auto status = mIGnssMeasurement_V2_0->setCallback_2_0(callback->getHidl(),
+                                                          options.enableFullTracking);
     if (!checkHidlReturn(status, "IGnssMeasurement setCallback_2_0() failed.")) {
         return JNI_FALSE;
     }
@@ -129,11 +146,15 @@
       : GnssMeasurement_V2_0{iGnssMeasurement}, mIGnssMeasurement_V2_1(iGnssMeasurement) {}
 
 jboolean GnssMeasurement_V2_1::setCallback(const std::unique_ptr<GnssMeasurementCallback>& callback,
-                                           bool enableFullTracking, bool enableCorrVecOutputs) {
-    if (enableCorrVecOutputs == true) {
+                                           const IGnssMeasurementInterface::Options& options) {
+    if (options.enableCorrVecOutputs == true) {
         ALOGW("Correlation vector output is not supported in 2.1 GNSS HAL.");
     }
-    auto status = mIGnssMeasurement_V2_1->setCallback_2_1(callback->getHidl(), enableFullTracking);
+    if (options.intervalMs > 1000) {
+        ALOGW("Measurement interval is not supported in 1.0 GNSS HAL.");
+    }
+    auto status = mIGnssMeasurement_V2_1->setCallback_2_1(callback->getHidl(),
+                                                          options.enableFullTracking);
     if (!checkHidlReturn(status, "IGnssMeasurement setCallback_2_1() failed.")) {
         return JNI_FALSE;
     }
diff --git a/services/core/jni/gnss/GnssMeasurement.h b/services/core/jni/gnss/GnssMeasurement.h
index f0752cd..7a95db8 100644
--- a/services/core/jni/gnss/GnssMeasurement.h
+++ b/services/core/jni/gnss/GnssMeasurement.h
@@ -37,16 +37,18 @@
 class GnssMeasurementInterface {
 public:
     virtual ~GnssMeasurementInterface() {}
-    virtual jboolean setCallback(const std::unique_ptr<GnssMeasurementCallback>& callback,
-                                 bool enableFullTracking, bool enableCorrVecOutputs) = 0;
+    virtual jboolean setCallback(
+            const std::unique_ptr<GnssMeasurementCallback>& callback,
+            const android::hardware::gnss::IGnssMeasurementInterface::Options& options) = 0;
     virtual jboolean close() = 0;
 };
 
 class GnssMeasurement : public GnssMeasurementInterface {
 public:
     GnssMeasurement(const sp<android::hardware::gnss::IGnssMeasurementInterface>& iGnssMeasurement);
-    jboolean setCallback(const std::unique_ptr<GnssMeasurementCallback>& callback,
-                         bool enableFullTracking, bool enableCorrVecOutputs) override;
+    jboolean setCallback(
+            const std::unique_ptr<GnssMeasurementCallback>& callback,
+            const android::hardware::gnss::IGnssMeasurementInterface::Options& options) override;
     jboolean close() override;
 
 private:
@@ -57,8 +59,9 @@
 public:
     GnssMeasurement_V1_0(
             const sp<android::hardware::gnss::V1_0::IGnssMeasurement>& iGnssMeasurement);
-    jboolean setCallback(const std::unique_ptr<GnssMeasurementCallback>& callback,
-                         bool enableFullTracking, bool enableCorrVecOutputs) override;
+    jboolean setCallback(
+            const std::unique_ptr<GnssMeasurementCallback>& callback,
+            const android::hardware::gnss::IGnssMeasurementInterface::Options& options) override;
     jboolean close() override;
 
 private:
@@ -69,8 +72,9 @@
 public:
     GnssMeasurement_V1_1(
             const sp<android::hardware::gnss::V1_1::IGnssMeasurement>& iGnssMeasurement);
-    jboolean setCallback(const std::unique_ptr<GnssMeasurementCallback>& callback,
-                         bool enableFullTracking, bool enableCorrVecOutputs) override;
+    jboolean setCallback(
+            const std::unique_ptr<GnssMeasurementCallback>& callback,
+            const android::hardware::gnss::IGnssMeasurementInterface::Options& options) override;
 
 private:
     const sp<android::hardware::gnss::V1_1::IGnssMeasurement> mIGnssMeasurement_V1_1;
@@ -80,8 +84,9 @@
 public:
     GnssMeasurement_V2_0(
             const sp<android::hardware::gnss::V2_0::IGnssMeasurement>& iGnssMeasurement);
-    jboolean setCallback(const std::unique_ptr<GnssMeasurementCallback>& callback,
-                         bool enableFullTracking, bool enableCorrVecOutputs) override;
+    jboolean setCallback(
+            const std::unique_ptr<GnssMeasurementCallback>& callback,
+            const android::hardware::gnss::IGnssMeasurementInterface::Options& options) override;
 
 private:
     const sp<android::hardware::gnss::V2_0::IGnssMeasurement> mIGnssMeasurement_V2_0;
@@ -91,8 +96,9 @@
 public:
     GnssMeasurement_V2_1(
             const sp<android::hardware::gnss::V2_1::IGnssMeasurement>& iGnssMeasurement);
-    jboolean setCallback(const std::unique_ptr<GnssMeasurementCallback>& callback,
-                         bool enableFullTracking, bool enableCorrVecOutputs) override;
+    jboolean setCallback(
+            const std::unique_ptr<GnssMeasurementCallback>& callback,
+            const android::hardware::gnss::IGnssMeasurementInterface::Options& options) override;
 
 private:
     const sp<android::hardware::gnss::V2_1::IGnssMeasurement> mIGnssMeasurement_V2_1;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 266b656..df8953c 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -7459,7 +7459,8 @@
         Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
 
         final CallerIdentity caller = getCallerIdentity();
-        Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle));
+        Preconditions.checkCallAuthorization(
+                hasFullCrossUsersPermission(caller, userHandle) && canQueryAdminPolicy(caller));
 
         synchronized (getLockObject()) {
             DevicePolicyData policy = getUserData(UserHandle.USER_SYSTEM);
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 663e17b..29797a5 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -1392,7 +1392,6 @@
         VcnManagementService vcnManagement = null;
         NetworkStatsService networkStats = null;
         NetworkPolicyManagerService networkPolicy = null;
-        NsdService serviceDiscovery = null;
         WindowManagerService wm = null;
         SerialService serial = null;
         NetworkTimeUpdateService networkTimeUpdater = null;
@@ -2008,16 +2007,6 @@
             }
             t.traceEnd();
 
-            t.traceBegin("StartNsdService");
-            try {
-                serviceDiscovery = NsdService.create(context);
-                ServiceManager.addService(
-                        Context.NSD_SERVICE, serviceDiscovery);
-            } catch (Throwable e) {
-                reportWtf("starting Service Discovery Service", e);
-            }
-            t.traceEnd();
-
             t.traceBegin("StartSystemUpdateManagerService");
             try {
                 ServiceManager.addService(Context.SYSTEM_UPDATE_SERVICE,
diff --git a/services/midi/java/com/android/server/midi/MidiService.java b/services/midi/java/com/android/server/midi/MidiService.java
index d0205ae..ca31efc 100644
--- a/services/midi/java/com/android/server/midi/MidiService.java
+++ b/services/midi/java/com/android/server/midi/MidiService.java
@@ -340,6 +340,11 @@
 
                 IBinder binder = server.asBinder();
                 mDevicesByServer.remove(binder);
+                // Clearing mDeviceStatus is needed because setDeviceStatus()
+                // relies on finding the device in mDevicesByServer.
+                // So the status can no longer be updated after we remove it.
+                // Then we can end up with input ports that are stuck open.
+                mDeviceStatus = null;
 
                 try {
                     server.closeDevice();
diff --git a/services/proguard.flags b/services/proguard.flags
index 30dd6cf..5d01d3e 100644
--- a/services/proguard.flags
+++ b/services/proguard.flags
@@ -1,11 +1,21 @@
 # TODO(b/196084106): Refine and optimize this configuration. Note that this
 # configuration is only used when `SOONG_CONFIG_ANDROID_SYSTEM_OPTIMIZE_JAVA=true`.
 -keep,allowoptimization,allowaccessmodification class ** {
-  *;
+  !synthetic *;
 }
 
 # Various classes subclassed in ethernet-service (avoid marking final).
 -keep public class android.net.** { *; }
 
 # Referenced via CarServiceHelperService in car-frameworks-service (avoid removing).
--keep public class com.android.server.utils.Slogf { *; }
\ No newline at end of file
+-keep public class com.android.server.utils.Slogf { *; }
+
+# Allows making private and protected methods/fields public as part of
+# optimization. This enables inlining of trivial getter/setter methods.
+-allowaccessmodification
+
+# Disallow accessmodification for soundtrigger classes. Logging via reflective
+# public member traversal can cause infinite loops. See b/210901706.
+-keep,allowoptimization class com.android.server.soundtrigger_middleware.** {
+  !synthetic *;
+}
diff --git a/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt b/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt
index 4b12fd4..8203c1b 100644
--- a/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt
+++ b/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt
@@ -354,6 +354,7 @@
                 PackageManager.PERMISSION_GRANTED
             }
         }
+        val mockSharedLibrariesImpl: SharedLibrariesImpl = mock()
         val mockInjector: PackageManagerServiceInjector = mock {
             whenever(this.lock) { PackageManagerTracedLock() }
             whenever(this.componentResolver) { mockComponentResolver }
@@ -366,6 +367,7 @@
             whenever(this.appsFilter) { mockAppsFilter }
             whenever(this.context) { mockContext }
             whenever(this.getHandler()) { testHandler }
+            whenever(this.sharedLibrariesImpl) { mockSharedLibrariesImpl }
         }
         val testParams = PackageManagerServiceTestParams().apply {
             this.pendingPackageBroadcasts = mockPendingBroadcasts
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 38e882e..334f503 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
@@ -301,6 +301,7 @@
                 whenever(isInstalled) { true }
                 whenever(isSuspended) { false }
                 whenever(isInstantApp) { false }
+                whenever(firstInstallTime) {0L}
             }
         })
         val pkg2 = mockPkgState(PKG_TWO, UUID_TWO, listOf(DOMAIN_1, DOMAIN_2))
@@ -548,7 +549,6 @@
         whenever(getPkg()) { pkg }
         whenever(packageName) { pkgName }
         whenever(this.domainSetId) { domainSetId }
-        whenever(firstInstallTime) { 0L }
         whenever(getUserStateOrDefault(0)) { pkgUserState0() }
         whenever(getUserStateOrDefault(1)) { pkgUserState1() }
         whenever(userStates) {
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 ad79c65..fb581d7 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
@@ -896,7 +896,6 @@
         whenever(this.pkg) { pkg }
         whenever(packageName) { pkgName }
         whenever(this.domainSetId) { domainSetId }
-        whenever(firstInstallTime) { 0L }
         whenever(getUserStateOrDefault(0)) { PackageUserStateInternal.DEFAULT }
         whenever(getUserStateOrDefault(10)) { PackageUserStateInternal.DEFAULT }
         whenever(userStates) {
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 9fa1a235..728da49 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
@@ -147,7 +147,6 @@
             whenever(this.pkg) { pkg }
             whenever(packageName) { pkgName }
             whenever(this.domainSetId) { domainSetId }
-            whenever(firstInstallTime) { 0L }
             whenever(getUserStateOrDefault(0)) { PackageUserStateInternal.DEFAULT }
             whenever(getUserStateOrDefault(1)) { PackageUserStateInternal.DEFAULT }
             whenever(userStates) {
diff --git a/services/tests/apexsystemservices/Android.bp b/services/tests/apexsystemservices/Android.bp
new file mode 100644
index 0000000..01e90a8
--- /dev/null
+++ b/services/tests/apexsystemservices/Android.bp
@@ -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 {
+    // 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"],
+}
+
+java_test_host {
+    name: "ApexSystemServicesTestCases",
+    srcs: ["src/**/*.java"],
+    libs: ["tradefed"],
+    java_resources: [
+        ":test_com.android.server",
+    ],
+    static_libs: [
+        "compatibility-host-util",
+        "cts-install-lib-host",
+        "frameworks-base-hostutils",
+        "truth-prebuilt",
+        "modules-utils-build-testing",
+    ],
+    test_suites: ["device-tests"],
+}
diff --git a/services/tests/apexsystemservices/AndroidTest.xml b/services/tests/apexsystemservices/AndroidTest.xml
new file mode 100644
index 0000000..edfefea
--- /dev/null
+++ b/services/tests/apexsystemservices/AndroidTest.xml
@@ -0,0 +1,24 @@
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT 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="Tests for apex-system-service support">
+    <option name="config-descriptor:metadata" key="component" value="misc" />
+    <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+    <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
+        <option name="jar" value="ApexSystemServicesTestCases.jar" />
+    </test>
+</configuration>
diff --git a/services/tests/apexsystemservices/OWNERS b/services/tests/apexsystemservices/OWNERS
new file mode 100644
index 0000000..0295b9e
--- /dev/null
+++ b/services/tests/apexsystemservices/OWNERS
@@ -0,0 +1,4 @@
+omakoto@google.com
+satayev@google.com
+
+include platform/packages/modules/common:/OWNERS
diff --git a/services/tests/apexsystemservices/apexes/test_com.android.server/Android.bp b/services/tests/apexsystemservices/apexes/test_com.android.server/Android.bp
new file mode 100644
index 0000000..16d6241
--- /dev/null
+++ b/services/tests/apexsystemservices/apexes/test_com.android.server/Android.bp
@@ -0,0 +1,40 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+apex_key {
+    name: "test_com.android.server.key",
+    public_key: "test_com.android.server.avbpubkey",
+    private_key: "test_com.android.server.pem",
+    installable: false,
+}
+
+android_app_certificate {
+    name: "test_com.android.server.certificate",
+    certificate: "test_com.android.server",
+}
+
+apex_test {
+    name: "test_com.android.server",
+    manifest: "manifest.json",
+    androidManifest: "AndroidManifest.xml",
+    java_libs: ["FakeApexSystemService"],
+    file_contexts: ":apex.test-file_contexts",
+    key: "test_com.android.server.key",
+    updatable: false,
+    installable: false,
+}
diff --git a/services/tests/apexsystemservices/apexes/test_com.android.server/AndroidManifest.xml b/services/tests/apexsystemservices/apexes/test_com.android.server/AndroidManifest.xml
new file mode 100644
index 0000000..eb741ca
--- /dev/null
+++ b/services/tests/apexsystemservices/apexes/test_com.android.server/AndroidManifest.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.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="test_com.android.server">
+    <!-- APEX does not have classes.dex -->
+    <application android:hasCode="false" android:testOnly="true">
+        <apex-system-service
+            android:name="com.android.server.testing.FakeApexSystemService"
+            android:path="/apex/test_com.android.server/javalib/FakeApexSystemService.jar"
+            android:minSdkVersion="30"/>
+
+        <!-- Always inactive system service, since maxSdkVersion is low -->
+        <apex-system-service
+            android:name="com.android.apex.test.OldApexSystemService"
+            android:path="/apex/com.android.apex.test/javalib/fake.jar"
+            android:minSdkVersion="1"
+            android:maxSdkVersion="1"
+        />
+
+        <!-- Always inactive system service, since minSdkVersion is high -->
+        <apex-system-service
+            android:name="com.android.apex.test.NewApexSystemService"
+            android:path="/apex/com.android.apex.test/javalib/fake.jar"
+            android:minSdkVersion="999999"
+        />
+    </application>
+</manifest>
diff --git a/services/tests/apexsystemservices/apexes/test_com.android.server/manifest.json b/services/tests/apexsystemservices/apexes/test_com.android.server/manifest.json
new file mode 100644
index 0000000..5e48532
--- /dev/null
+++ b/services/tests/apexsystemservices/apexes/test_com.android.server/manifest.json
@@ -0,0 +1,4 @@
+{
+  "name": "test_com.android.server",
+  "version": 1
+}
diff --git a/services/tests/apexsystemservices/apexes/test_com.android.server/test_com.android.server.avbpubkey b/services/tests/apexsystemservices/apexes/test_com.android.server/test_com.android.server.avbpubkey
new file mode 100644
index 0000000..4f4acd6
--- /dev/null
+++ b/services/tests/apexsystemservices/apexes/test_com.android.server/test_com.android.server.avbpubkey
Binary files differ
diff --git a/services/tests/apexsystemservices/apexes/test_com.android.server/test_com.android.server.pem b/services/tests/apexsystemservices/apexes/test_com.android.server/test_com.android.server.pem
new file mode 100644
index 0000000..f391ef0
--- /dev/null
+++ b/services/tests/apexsystemservices/apexes/test_com.android.server/test_com.android.server.pem
@@ -0,0 +1,51 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIJKQIBAAKCAgEAur/sf1yom0DzYXRG4HaigR2qjUwPOtxr+cfVem0OxZeSTc5X
+W8cueEFcYvE3G3FOpxfv5FBtSFvAJaV+N8v8pWRoTgIxA0Squf0oH+PPqT11GQ6r
+Nhw78Wvw8+CdWJDE0ATK6Jlvail65KbcjgwkQyLhBXLNV2mX4BW7QimVbma49B6V
+P0NDW3ymbG7iO8CiuAVsN4SIpGa12W0Dwh/UBBXPkBcybo/tRQL9tcpismI46/Qj
+t6VvWwNn7M97zpGtvLLUqB+tinamo+cYJtNmkgIP3w3pvritYYuILIFBgzSx3MMb
+VtfQ/0fgtNJJkfHS5qb7kd1PRzcehVX9Ej6UCQN/iP+fv7vtP9l9cJZ4nxHDzkBg
+/oxqzdCWks1SU3Kq2+OGKg6B/4+H64Igf5B48/mmZ8Ss3xHPS2bq5lGE998hVtUL
+D7KhnX8F5J9X+yE0hME6Biekpo/w/8JHATl5iidRDfhYWwawkjuHExtdY4TibfuC
+y4ol7mv3UQEdzfsNKSUIEWurVbKfqDmj29MiyF0F7VCak3NlB3ZZyIvEiglQTqoh
+uNKkfFYHccZQhihk1CpQ6cv31H+QcEAN+osGk0dKm5h6kf1hUfn02KMFSnv7u/yk
+QOhLmNpPekbLrqvYvNAwYU/lQ6qZIuyIXudZaJ3MoWq5YtCEeexBQPP5sa0CAwEA
+AQKCAgAHyasmIIoTd2Du5ndyMuBR/Be5rrtP3BNQpkm7wkKEcO6z+e/gruy8LRWa
+Nq7yoQYDp9bkMYptIw5fQ4iA8SvHBennnuXGWh24hdsfgVOOnjZ85gSzy/ef+L1i
+njJRmC/s8NY5XvSre7FZSbAW6GC2wAScQo5Xn9qqiJ13g95sbTI3U/MrYTW04fza
+tsEOdtkSTX+WzRsZqALbX1VxyfwAc5xlSOJcg/oED7ze0OLOx5PSGytGJEsBg6HY
+2UozchXJsbd2j2OgS5Rlb2StcdFsM1PQHHdr8a2hTL1QBc/ildb4+tXwCC36B1hS
+khZpVKlT3xDMo2sD8EOAkfZsxVlM+K5Yq98nZx92AxSYC+tmHf87YHPvV1fDyKv9
+w/fG77mR1EqaQCMsWeYZFSa7KDKRaKFt8MlGCQYYzQyHxXf+DFq9z375TMLQB1NX
+RZp5aDjlzLQYD75N6nyo5uboE+YG40WEgWoc96j1nnVG37DO6jxpHipEJB9yAYiS
+m4jzsl1msMmnUDqswCZgiTOtdxsgjbQqwLlS/t6cycnjrcPQo0Fz1AxBQ2BIKTCQ
+wBn1CE+S/2grTnM8vWXVbZSOg4gulrcaLd1ec8gWme0Vz0JTUBtwslAK14s2wTTE
+PlI5ZqsnXy3rVbGkh4gNTZdi/4xvtJodi4dItp6azsJDd4V/jQKCAQEA4e4Dlpwz
+/TgBNn+htMsGgtAXTXEGn3WSkyei0QYkDwWkrL+EOyNJXKcBl8IMK4yy7vumy6fn
+PmRc9+gu52mzm7pqpmqzW5xgJMfvW57wKDTrhxbRSThXf4wBLiuMz9VutZWwY2kA
+zsfroOmERSxWba8tdFlgP6hSjlSP0wolg71ba9n8oFJIN7m6sDadOUtH+xFGkX4T
+QSC1o0ofq0mx+Q8mXI1LDgZofaJacaBcI1FeoaR1tzPU2OoOXz7XkSG5X7osu+e9
+afW1c5dQH2FU3by7JGZv+z3rlsWsUI0OHnsDm4k6om7HGdF0oUqxnXlT4zYa1y7j
+MIDHsp1p7wonewKCAQEA05ry49TfXcW3y35ns+zp06xNmYwKui3L01OLe0NjnCy0
+RsDKGa0pT/fFXGH7OOx6cVgtVCPlWFKv8S5KMgU0rnyLfhQn6NqjuIh2oMLIls3D
+mnCxjwzkHMx2nF4+Sih7nYgOJ/BY1afmErXJkh+SYPtMRsZJoIS3OCkQaikWN7Ne
+nPP/EumuU+tj4aTSbrK4mbcpPS8S3YhDLKPNQNHrWlbJjkxGFico+HSlXZ068vDd
+sldVlJL9z8+dCe6B2wLobtpBP1gR0mjb8CXrBdQ9VC0hdwlYsUlpCGI71BrfCkUV
+oHCWRlWWZvLg0L/qpgF/UlmgXnI3Ii+WXwH1A4iu9wKCAQBdy7qhpGfREJcwUPyJ
+WmBxnoKOHAZr3RvlC+eEb9A4jFc5gKkdBCFI3ezDXERBMEB5BvDQS/ys4m3WXgZa
+/H8cf+AXBuU/e0RPANJWbz2084N0qfxpMYLh6PX0fRAQmMNFj8eS/dzf/A/O1iOb
+tDSNhNSSISjcRL1BacnsC6JXdx2lQPKofICO4gSnc4UCbEaN7TYm4PiNaU7/Y56S
+Nh41EB0U/3PRdseaoPR7h9+4qednpCdaz6HmDAW7dRN5pU6Yd2pq+GKiwud5/a+9
+12KsS9ZF3mFPJP3Rsm8/YdAix19QC0DUfrkZ9uM8sw3aGqzA/41VGJopYM2HUeLQ
+4p5RAoIBAQDOWvH5GrQFN3aIXSn2fdh9ky9NyRMBAv4dhQCl4U73k2TvBr1QEt0R
+3he6gtbCaWLyu8HgpuzWmDR6J+E1LHx2mIBUIIXW/7jfkTzWg32oCttw9etCDJk8
+OGyHCyUFnrsGIhNkAXAwU377ygnblSxjpU16S46rmiEvBGS8knrXMPXYa93Y7MgT
+kJ8kAl8wktuRE9yEjS6BmYugsdDNIKm6vJ3sRhenLOM4gFBvnZBKMHiSnbaYoEwi
+Z13GvLAoC4rt56vvgQxIO/gYFnI+if6Q4z4aXqP+qA9knJ+ptdbCpiJ0BreVuYtl
+s/9ns3C6GQW4Ii1RTWLU1MF4v2jX3Gh7AoIBAQCDoeQeJFpoU7yF34RN8reZjxZ4
+nF2Yj2B4vpdeT28iMPhl01Ctay7m0FQcc2CdtRcogtYIvxT+6sMeXvIM1hAEjaTn
+ps3GusyAFrn58oZzxhoKPmQfNVVqFM9BDeixhKv0HjOvc/sJaWnMWtYkUil8NoOk
+o/Py8a3tcGDv/a2rPn4ZBOAiGe0oO9ed/lNKqmxcGaEEhRuboZcvwPgq6eY6UV4r
+IJ9CB3zV8nPXKQXLAatg5xaS25YrLofL02wnUtm/k3fWyIxX2pFg19KiKuG7ywpY
+OnaWweSoDhPOeYVQjP9U9CzcaofffsNP/1dvqJRDm6fRBE3qaGhIcTFMC3xy
+-----END RSA PRIVATE KEY-----
diff --git a/services/tests/apexsystemservices/apexes/test_com.android.server/test_com.android.server.pk8 b/services/tests/apexsystemservices/apexes/test_com.android.server/test_com.android.server.pk8
new file mode 100644
index 0000000..ca45333
--- /dev/null
+++ b/services/tests/apexsystemservices/apexes/test_com.android.server/test_com.android.server.pk8
Binary files differ
diff --git a/services/tests/apexsystemservices/apexes/test_com.android.server/test_com.android.server.x509.pem b/services/tests/apexsystemservices/apexes/test_com.android.server/test_com.android.server.x509.pem
new file mode 100644
index 0000000..13a3058
--- /dev/null
+++ b/services/tests/apexsystemservices/apexes/test_com.android.server/test_com.android.server.x509.pem
@@ -0,0 +1,34 @@
+-----BEGIN CERTIFICATE-----
+MIIF3TCCA8UCFBYj125aAL6TlF+vGODQhEUq6/AXMA0GCSqGSIb3DQEBCwUAMIGp
+MQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91
+bnRhaW4gVmlldzEQMA4GA1UECgwHQW5kcm9pZDEQMA4GA1UECwwHQW5kcm9pZDEi
+MCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTElMCMGA1UEAwwcdGVz
+dF9jb20uYW5kcm9pZC5zZXJ2ZXIuYXBleDAgFw0yMTEyMTQxNTUyMjBaGA80NzU5
+MTExMDE1NTIyMFowgakxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlh
+MRYwFAYDVQQHDA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdBbmRyb2lkMRAwDgYD
+VQQLDAdBbmRyb2lkMSIwIAYJKoZIhvcNAQkBFhNhbmRyb2lkQGFuZHJvaWQuY29t
+MSUwIwYDVQQDDBx0ZXN0X2NvbS5hbmRyb2lkLnNlcnZlci5hcGV4MIICIjANBgkq
+hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAsiWlZYCPg2ZyOQbxwwH9F2SCM5h7KIQS
+RIsHkbTiXWmrIV3SS4LX6u3Phf/Uo275aFgLX+BqBPx4FPdN2FQYpqiS7BZ1dQm6
+vGFYSCPPVt8HIs5eEswwPt3cJUe+7jaeAW5n+kuV2lmv/K5Xr4HWhG6ywAvMzK5M
+uHKkz7Q6BgkFyDBAq7iyGNaxBRu0v+RIzZkSq/UDjPsG4o+lBiY+jhcMV37NZvTo
+3xqq2ia0wKK5GUsaZ6OGYP22+RtSu/jIV1LWE9ukucFes8BfnBGKq9DvF+qviPuV
+BsGckuet2Oa2Ty44ffviWmKTEJi4/MZ7o+uiP4bWyh3C1iP7acXNDDEt3nEiceF7
+1wKJkYMay8IZ3VWczQieZWN5oxNBZSE+kMi+ZOolcs2tRi2EO0KsjVN63fhi75WZ
+kGTl4J/G0irWBHOBHvosL4EcEboV1B2QsfDvjvpAIQkhqG0IKrN2czN+xzcMeJRr
+CXRRLLkdTS1DLXKaTTZg/U1MfhRfrqY8OCOKT2IhmqmKajhOIXXrKNt+0VfHjweL
+RbF7mgwb7jyKe3Cy1WlEqQXuZRbHSQ6aSfQ/nbMFaj+MQn3KULBciHGjZB0fQC4Z
+P+CMwZpdbBRA2VdrOZ8cvOxp88MrdSaz6RuSbQIu70THM7hmzXd9iEzjmmJ6bbaJ
+P9/nR38HoxUCAwEAATANBgkqhkiG9w0BAQsFAAOCAgEAkSVfES3KoY8z1nb0KEcS
+LCldTE0X+5vZ6n+8Bwy04Tb6Evdhui2dtgtKTwQMSZ4qS6bUnnwJgAcswV2LCeui
+sosUNB4prNdlLZeZmCg+SimNM9AZIpJaMAtlbCiAMRb0yN+I7nAIcNv/HhGLVYte
+JGyoxkm73m82YCyRPG8FPsKMufoDeUo3mOnVXKLYgeq5er2YN1bWYjCE5X6mWV85
+iyGGK/X6h4ANybxqp4sFLOwQzgm7HfYrsm0RadN95PhUiSqlVGJHo/EJixK0sNYS
+VzDtGqo+i3wWww9rVUiMroRRMf6thXY4O1TqU2Sn2H3OMasIUT+w1Y1KONpJyE58
+2Yi+865msa2l8BGH8qPNgHERLlMZcIm5LfFTHw/9QniJdfHo6PEJoSzSmT4yDOMa
+WYmafNdR3FfKdGGGHJZWVUtMSxlGe7DjzVhm0M3vHgEldsEMLnwOjecDQq3ssXsC
+0mOCabaSpAZA0p0c2sQuhzij1mFxNaEEhbEZ93klz2+e1u7Q/xPiGMYCQky/+WsL
+aYBuo0AbCtTEvy92vhTc0KphVoeY7X/VEojkDfmm8wHvAtOBr03t6jLGWmGcGPJp
+/Opxik2IZKAm27HeN1ICJGUTiky5ULj1DmrdiMQhkvz0jNoNJvjJsbeQnOs0te6J
+bR8InfVgdeIr68zrlvC+SfE=
+-----END CERTIFICATE-----
diff --git a/services/tests/apexsystemservices/service/Android.bp b/services/tests/apexsystemservices/service/Android.bp
new file mode 100644
index 0000000..9d04f39
--- /dev/null
+++ b/services/tests/apexsystemservices/service/Android.bp
@@ -0,0 +1,20 @@
+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"],
+}
+
+java_library {
+    name: "FakeApexSystemService",
+    srcs: ["**/*.java"],
+    sdk_version: "system_server_current",
+    libs: [
+        "framework-annotations-lib",
+        "androidx.annotation_annotation",
+    ],
+    visibility: ["//frameworks/base/services/tests/apexsystemservices:__subpackages__"],
+    apex_available: ["//apex_available:anyapex"],
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpDrawable.java b/services/tests/apexsystemservices/service/src/com/android/server/testing/FakeApexSystemService.java
similarity index 63%
rename from packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpDrawable.java
rename to services/tests/apexsystemservices/service/src/com/android/server/testing/FakeApexSystemService.java
index 09b6fab..4947c34 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpDrawable.java
+++ b/services/tests/apexsystemservices/service/src/com/android/server/testing/FakeApexSystemService.java
@@ -14,28 +14,28 @@
  * limitations under the License.
  */
 
-package com.android.systemui.biometrics;
+package com.android.server.testing;
 
 import android.content.Context;
-import android.graphics.Canvas;
+import android.util.Log;
 
 import androidx.annotation.NonNull;
 
-/**
- * Draws udfps fingerprint if sensor isn't illuminating.
- */
-public class UdfpsFpDrawable extends UdfpsDrawable {
+import com.android.server.SystemService;
 
-    UdfpsFpDrawable(@NonNull Context context) {
+/**
+ * A fake system service that just logs when it is started.
+ */
+public class FakeApexSystemService extends SystemService {
+
+    private static final String TAG = "FakeApexSystemService";
+
+    public FakeApexSystemService(@NonNull Context context) {
         super(context);
     }
 
     @Override
-    public void draw(@NonNull Canvas canvas) {
-        if (isIlluminationShowing()) {
-            return;
-        }
-
-        mFingerprintDrawable.draw(canvas);
+    public void onStart() {
+        Log.d(TAG, "FakeApexSystemService onStart");
     }
 }
diff --git a/services/tests/apexsystemservices/src/com/android/server/ApexSystemServicesTestCases.java b/services/tests/apexsystemservices/src/com/android/server/ApexSystemServicesTestCases.java
new file mode 100644
index 0000000..2b453a9
--- /dev/null
+++ b/services/tests/apexsystemservices/src/com/android/server/ApexSystemServicesTestCases.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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 static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assume.assumeTrue;
+
+import android.cts.install.lib.host.InstallUtilsHost;
+
+import com.android.internal.util.test.SystemPreparer;
+import com.android.modules.utils.build.testing.DeviceSdkLevel;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.RuleChain;
+import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class ApexSystemServicesTestCases extends BaseHostJUnit4Test {
+
+    private final InstallUtilsHost mHostUtils = new InstallUtilsHost(this);
+    private final TemporaryFolder mTemporaryFolder = new TemporaryFolder();
+    private final SystemPreparer mPreparer = new SystemPreparer(mTemporaryFolder, this::getDevice);
+
+    @Rule
+    public final RuleChain ruleChain = RuleChain.outerRule(mTemporaryFolder).around(mPreparer);
+
+    private DeviceSdkLevel mDeviceSdkLevel;
+    private ITestDevice mDevice;
+
+    @Before
+    public void setup() throws Exception {
+        mDevice = getDevice();
+        mDeviceSdkLevel = new DeviceSdkLevel(getDevice());
+
+        assumeTrue(mDeviceSdkLevel.isDeviceAtLeastT());
+
+        assertThat(mDevice.enableAdbRoot()).isTrue();
+        assertThat(mHostUtils.isApexUpdateSupported()).isTrue();
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        mDevice.disableAdbRoot();
+    }
+
+    @Test
+    public void noApexSystemServerStartsWithoutApex() throws Exception {
+        mPreparer.reboot();
+
+        assertThat(getFakeApexSystemServiceLogcat())
+                .doesNotContain("FakeApexSystemService onStart");
+    }
+
+    @Test
+    public void apexSystemServerStarts() throws Exception {
+        // Pre-install the apex
+        String apex = "test_com.android.server.apex";
+        mPreparer.pushResourceFile(apex, "/system/apex/" + apex);
+        // Reboot activates the apex
+        mPreparer.reboot();
+
+        assertThat(getFakeApexSystemServiceLogcat())
+                .contains("FakeApexSystemService onStart");
+    }
+
+    private String getFakeApexSystemServiceLogcat() throws DeviceNotAvailableException {
+        return mDevice.executeAdbCommand("logcat", "-v", "brief", "-d", "FakeApexSystemService:D",
+                "*:S");
+    }
+
+}
diff --git a/services/tests/mockingservicestests/Android.bp b/services/tests/mockingservicestests/Android.bp
index 48a8b1b..8538603 100644
--- a/services/tests/mockingservicestests/Android.bp
+++ b/services/tests/mockingservicestests/Android.bp
@@ -59,6 +59,7 @@
         "mockingservicestests-utils-mockito",
         "servicestests-core-utils",
         "testables",
+        "kotlin-test",
         // TODO: remove once Android migrates to JUnit 4.12, which provides assertThrows
         "testng",
     ],
diff --git a/services/tests/mockingservicestests/assets/GameServiceSelectorTest/game_service_metadata_valid.xml b/services/tests/mockingservicestests/assets/GameServiceSelectorTest/game_service_metadata_valid.xml
new file mode 100644
index 0000000..4720085
--- /dev/null
+++ b/services/tests/mockingservicestests/assets/GameServiceSelectorTest/game_service_metadata_valid.xml
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>
+<game-service xmlns:android="http://schemas.android.com/apk/res/android"
+     android:sessionService="com.game.service.provider.GameSessionService"/>
diff --git a/services/tests/mockingservicestests/res/xml/game_service_metadata_no_session_service.xml b/services/tests/mockingservicestests/res/xml/game_service_metadata_no_session_service.xml
new file mode 100644
index 0000000..ebd5103
--- /dev/null
+++ b/services/tests/mockingservicestests/res/xml/game_service_metadata_no_session_service.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8"?>
+<game-service/>
diff --git a/services/tests/mockingservicestests/res/xml/game_service_metadata_valid.xml b/services/tests/mockingservicestests/res/xml/game_service_metadata_valid.xml
new file mode 100644
index 0000000..8ee3cce
--- /dev/null
+++ b/services/tests/mockingservicestests/res/xml/game_service_metadata_valid.xml
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>
+<game-service xmlns:android="http://schemas.android.com/apk/res/android"
+     android:gameSessionService="com.game.service.provider.GameSessionService"/>
diff --git a/services/tests/mockingservicestests/res/xml/game_service_metadata_wrong_first_tag.xml b/services/tests/mockingservicestests/res/xml/game_service_metadata_wrong_first_tag.xml
new file mode 100644
index 0000000..6bc0eac
--- /dev/null
+++ b/services/tests/mockingservicestests/res/xml/game_service_metadata_wrong_first_tag.xml
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>
+<wrong-tag xmlns:android="http://schemas.android.com/apk/res/android"
+           android:gameSessionService="com.game.service.provider.GameSessionService"/>
diff --git a/services/tests/mockingservicestests/src/com/android/server/app/FakeGameClassifier.java b/services/tests/mockingservicestests/src/com/android/server/app/FakeGameClassifier.java
new file mode 100644
index 0000000..060b773
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/app/FakeGameClassifier.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.server.app;
+
+import android.annotation.NonNull;
+import android.os.UserHandle;
+
+import java.util.HashSet;
+
+/**
+ * Fake implementation of {@link GameClassifier} used for tests.
+ *
+ * By default, all packages are considers not games. A package may be marked as a game using
+ * {@link #recordGamePackage(String)}.
+ */
+final class FakeGameClassifier implements GameClassifier {
+    private final HashSet<String> mGamePackages = new HashSet<>();
+
+    /**
+     * Marks the given {@code packageName} as a game.
+     */
+    public void recordGamePackage(String packageName) {
+        mGamePackages.add(packageName);
+    }
+
+    @Override
+    public boolean isGame(@NonNull String packageName, UserHandle userHandle) {
+        return mGamePackages.contains(packageName);
+    }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/app/FakeGameServiceProviderInstance.java b/services/tests/mockingservicestests/src/com/android/server/app/FakeGameServiceProviderInstance.java
new file mode 100644
index 0000000..98142f5
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/app/FakeGameServiceProviderInstance.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.app;
+
+
+/**
+ * Fake implementation of {@link GameServiceProviderInstance} used for tests.
+ */
+final class FakeGameServiceProviderInstance implements GameServiceProviderInstance {
+    private boolean mRunning;
+
+    @Override
+    public void start() {
+        mRunning = true;
+    }
+
+    @Override
+    public void stop() {
+        mRunning = false;
+    }
+
+    /**
+     * Returns {@code true} if the instance is currently running.
+     */
+    public boolean getIsRunning() {
+        return mRunning;
+    }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/app/FakeServiceConnector.java b/services/tests/mockingservicestests/src/com/android/server/app/FakeServiceConnector.java
new file mode 100644
index 0000000..0ae509e
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/app/FakeServiceConnector.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.app;
+
+
+import android.os.IInterface;
+
+import com.android.internal.infra.AndroidFuture;
+import com.android.internal.infra.ServiceConnector;
+
+import java.util.concurrent.CompletableFuture;
+
+/**
+ * Fake implementation of {@link ServiceConnector<T>} used for tests.
+ *
+ * Tests provide a service instance via {@link #FakeServiceConnector(IInterface)} that will be
+ * connected to and used to fulfill service jobs.
+ */
+final class FakeServiceConnector<T extends IInterface> implements
+        ServiceConnector<T> {
+    private final T mService;
+    private boolean mIsConnected;
+    private int mConnectCount = 0;
+
+    FakeServiceConnector(T service) {
+        mService = service;
+    }
+
+    @Override
+    public boolean run(VoidJob<T> job) {
+        AndroidFuture<Void> unusedFuture = post(job);
+        return true;
+    }
+
+    @Override
+    public AndroidFuture<Void> post(VoidJob<T> job) {
+        markPossibleConnection();
+
+        return postForResult(job);
+    }
+
+    @Override
+    public <R> AndroidFuture<R> postForResult(Job<T, R> job) {
+        markPossibleConnection();
+
+        AndroidFuture<R> androidFuture = new AndroidFuture();
+        try {
+            androidFuture.complete(job.run(mService));
+        } catch (Exception ex) {
+            androidFuture.completeExceptionally(ex);
+        }
+        return androidFuture;
+    }
+
+    @Override
+    @SuppressWarnings("FutureReturnValueIgnored")
+    public <R> AndroidFuture<R> postAsync(Job<T, CompletableFuture<R>> job) {
+        markPossibleConnection();
+        AndroidFuture<R> androidFuture = new AndroidFuture();
+
+        try {
+            CompletableFuture<R> future = job.run(mService);
+            future.whenComplete((result, exception) -> {
+                if (exception != null) {
+                    androidFuture.completeExceptionally(exception);
+                } else {
+                    androidFuture.complete(result);
+                }
+            });
+        } catch (Exception ex) {
+            androidFuture.completeExceptionally(ex);
+        }
+
+        return androidFuture;
+    }
+
+    @Override
+    public AndroidFuture<T> connect() {
+        markPossibleConnection();
+        return AndroidFuture.completedFuture(mService);
+    }
+
+    @Override
+    public void unbind() {
+        mIsConnected = false;
+    }
+
+    private void markPossibleConnection() {
+        if (mIsConnected) {
+            return;
+        }
+
+        mConnectCount += 1;
+        mIsConnected = true;
+    }
+
+    /**
+     * Returns {@code true} if the underlying service is connected.
+     */
+    public boolean getIsConnected() {
+        return mIsConnected;
+    }
+
+    /**
+     * Returns the number of times a connection was established with the underlying service.
+     */
+    public int getConnectCount() {
+        return mConnectCount;
+    }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/app/GameServiceControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/app/GameServiceControllerTest.java
new file mode 100644
index 0000000..0545fde
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/app/GameServiceControllerTest.java
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.app;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import android.content.ComponentName;
+import android.content.pm.UserInfo;
+import android.os.UserHandle;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.util.ConcurrentUtils;
+import com.android.server.SystemService;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
+
+
+/** Unit tests for {@link GameServiceController}. */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@Presubmit
+public final class GameServiceControllerTest {
+    private static final UserHandle USER_HANDLE_10 = new UserHandle(10);
+    private static final UserHandle USER_HANDLE_11 = new UserHandle(11);
+    private static final SystemService.TargetUser USER_10 = user(10);
+    private static final SystemService.TargetUser USER_11 = user(11);
+    private static final String PROVIDER_A_PACKAGE_NAME = "com.provider.a";
+    private static final ComponentName PROVIDER_A_SERVICE_A =
+            new ComponentName(PROVIDER_A_PACKAGE_NAME, "com.provider.a.ServiceA");
+    private static final ComponentName PROVIDER_A_SERVICE_B =
+            new ComponentName(PROVIDER_A_PACKAGE_NAME, "com.provider.a.ServiceB");
+
+    private MockitoSession mMockingSession;
+    private GameServiceController mGameServiceManager;
+    @Mock
+    private GameServiceProviderSelector mMockGameServiceProviderSelector;
+    @Mock
+    private GameServiceProviderInstanceFactory mMockGameServiceProviderInstanceFactory;
+
+    @Before
+    public void setUp() throws Exception {
+        mMockingSession = mockitoSession()
+                .initMocks(this)
+                .strictness(Strictness.LENIENT)
+                .startMocking();
+
+        mGameServiceManager = new GameServiceController(
+                ConcurrentUtils.DIRECT_EXECUTOR,
+                mMockGameServiceProviderSelector,
+                mMockGameServiceProviderInstanceFactory);
+    }
+
+    @After
+    public void tearDown() {
+        mMockingSession.finishMocking();
+    }
+
+    @Test
+    public void notifyUserStarted_hasNotCompletedBoot_doesNothing() {
+        mGameServiceManager.notifyUserStarted(USER_10);
+
+        verifyNoMoreInteractions(mMockGameServiceProviderInstanceFactory);
+    }
+
+    @Test
+    public void notifyUserStarted_createsAndStartsNewInstance() {
+        GameServiceProviderConfiguration configurationA =
+                new GameServiceProviderConfiguration(USER_HANDLE_10, PROVIDER_A_SERVICE_A,
+                        PROVIDER_A_SERVICE_B);
+        FakeGameServiceProviderInstance instanceA =
+                seedConfigurationForUser(USER_10, configurationA);
+
+        mGameServiceManager.onBootComplete();
+        mGameServiceManager.notifyUserStarted(USER_10);
+
+        verify(mMockGameServiceProviderInstanceFactory).create(configurationA);
+        verifyNoMoreInteractions(mMockGameServiceProviderInstanceFactory);
+        assertThat(instanceA.getIsRunning()).isTrue();
+    }
+
+    @Test
+    public void notifyUserStarted_sameUser_doesNotCreateNewInstance() {
+        GameServiceProviderConfiguration configurationA =
+                new GameServiceProviderConfiguration(USER_HANDLE_10, PROVIDER_A_SERVICE_A,
+                        PROVIDER_A_SERVICE_B);
+        FakeGameServiceProviderInstance instanceA =
+                seedConfigurationForUser(USER_10, configurationA);
+
+        mGameServiceManager.onBootComplete();
+        mGameServiceManager.notifyUserStarted(USER_10);
+        mGameServiceManager.notifyUserStarted(USER_10);
+
+        verify(mMockGameServiceProviderInstanceFactory).create(configurationA);
+        verifyNoMoreInteractions(mMockGameServiceProviderInstanceFactory);
+        assertThat(instanceA.getIsRunning()).isTrue();
+    }
+
+    @Test
+    public void notifyUserUnlocking_noForegroundUser_ignores() {
+        GameServiceProviderConfiguration configurationA =
+                new GameServiceProviderConfiguration(USER_HANDLE_10, PROVIDER_A_SERVICE_A,
+                        PROVIDER_A_SERVICE_B);
+        FakeGameServiceProviderInstance instanceA =
+                seedConfigurationForUser(USER_10, configurationA);
+
+        mGameServiceManager.onBootComplete();
+        mGameServiceManager.notifyUserUnlocking(USER_10);
+
+        verifyNoMoreInteractions(mMockGameServiceProviderInstanceFactory);
+        assertThat(instanceA.getIsRunning()).isFalse();
+    }
+
+    @Test
+    public void notifyUserUnlocking_sameAsForegroundUser_evaluatesProvider() {
+        GameServiceProviderConfiguration configurationA =
+                new GameServiceProviderConfiguration(USER_HANDLE_10, PROVIDER_A_SERVICE_A,
+                        PROVIDER_A_SERVICE_B);
+        seedNoConfigurationForUser(USER_10);
+
+        mGameServiceManager.onBootComplete();
+        mGameServiceManager.notifyUserStarted(USER_10);
+        FakeGameServiceProviderInstance instanceA =
+                seedConfigurationForUser(USER_10, configurationA);
+        mGameServiceManager.notifyUserUnlocking(USER_10);
+
+        verify(mMockGameServiceProviderInstanceFactory).create(configurationA);
+        verifyNoMoreInteractions(mMockGameServiceProviderInstanceFactory);
+        assertThat(instanceA.getIsRunning()).isTrue();
+    }
+
+    @Test
+    public void notifyUserUnlocking_differentFromForegroundUser_ignores() {
+        GameServiceProviderConfiguration configurationA =
+                new GameServiceProviderConfiguration(USER_HANDLE_10, PROVIDER_A_SERVICE_A,
+                        PROVIDER_A_SERVICE_B);
+        seedNoConfigurationForUser(USER_10);
+
+        mGameServiceManager.onBootComplete();
+        mGameServiceManager.notifyUserStarted(USER_10);
+        FakeGameServiceProviderInstance instanceA =
+                seedConfigurationForUser(USER_11, configurationA);
+        mGameServiceManager.notifyUserUnlocking(USER_11);
+
+        verifyNoMoreInteractions(mMockGameServiceProviderInstanceFactory);
+        assertThat(instanceA.getIsRunning()).isFalse();
+    }
+
+    @Test
+    public void
+            notifyNewForegroundUser_differentUser_stopsPreviousInstanceAndThenStartsNewInstance() {
+        GameServiceProviderConfiguration configurationA =
+                new GameServiceProviderConfiguration(USER_HANDLE_10, PROVIDER_A_SERVICE_A,
+                        PROVIDER_A_SERVICE_B);
+        FakeGameServiceProviderInstance instanceA =
+                seedConfigurationForUser(USER_10, configurationA);
+        GameServiceProviderConfiguration configurationB =
+                new GameServiceProviderConfiguration(USER_HANDLE_11, PROVIDER_A_SERVICE_A,
+                        PROVIDER_A_SERVICE_B);
+        FakeGameServiceProviderInstance instanceB = seedConfigurationForUser(USER_11,
+                configurationB);
+        InOrder instancesInOrder = Mockito.inOrder(instanceA, instanceB);
+
+        mGameServiceManager.onBootComplete();
+        mGameServiceManager.notifyUserStarted(USER_10);
+        mGameServiceManager.notifyNewForegroundUser(USER_11);
+
+        verify(mMockGameServiceProviderInstanceFactory).create(configurationA);
+        verify(mMockGameServiceProviderInstanceFactory).create(configurationB);
+        instancesInOrder.verify(instanceA).start();
+        instancesInOrder.verify(instanceA).stop();
+        instancesInOrder.verify(instanceB).start();
+        verifyNoMoreInteractions(mMockGameServiceProviderInstanceFactory);
+        assertThat(instanceA.getIsRunning()).isFalse();
+        assertThat(instanceB.getIsRunning()).isTrue();
+    }
+
+    private void seedNoConfigurationForUser(SystemService.TargetUser user) {
+        when(mMockGameServiceProviderSelector.get(user)).thenReturn(null);
+    }
+
+    private FakeGameServiceProviderInstance seedConfigurationForUser(SystemService.TargetUser user,
+            GameServiceProviderConfiguration configuration) {
+        when(mMockGameServiceProviderSelector.get(user)).thenReturn(configuration);
+        FakeGameServiceProviderInstance instanceForConfiguration =
+                spy(new FakeGameServiceProviderInstance());
+        when(mMockGameServiceProviderInstanceFactory.create(configuration))
+                .thenReturn(instanceForConfiguration);
+
+        return instanceForConfiguration;
+    }
+
+    private static SystemService.TargetUser user(int userId) {
+        UserInfo userInfo = new UserInfo(userId, "", "", UserInfo.FLAG_FULL);
+        return new SystemService.TargetUser(userInfo);
+    }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/app/GameServiceControllerTests.java b/services/tests/mockingservicestests/src/com/android/server/app/GameServiceControllerTests.java
deleted file mode 100644
index 8973a89..0000000
--- a/services/tests/mockingservicestests/src/com/android/server/app/GameServiceControllerTests.java
+++ /dev/null
@@ -1,455 +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.app;
-
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
-
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.argThat;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
-import android.content.pm.UserInfo;
-import android.content.res.Resources;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.platform.test.annotations.Presubmit;
-import android.service.games.GameService;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.server.SystemService;
-
-import com.google.common.collect.ImmutableList;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.InOrder;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.MockitoSession;
-
-import java.util.List;
-
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-@Presubmit
-public final class GameServiceControllerTests {
-    @Mock
-    private PackageManager mMockPackageManager;
-    @Mock
-    private Resources mMockResources;
-    @Mock
-    private Context mMockContext;
-    private MockitoSession mMockingSession;
-
-    private static UserInfo eligibleUserInfo(int uid) {
-        return new UserInfo(uid, "", "", UserInfo.FLAG_FULL);
-    }
-
-    private static UserInfo managedUserInfo(int uid) {
-        UserInfo userInfo = eligibleUserInfo(uid);
-        userInfo.userType = UserManager.USER_TYPE_PROFILE_MANAGED;
-        return userInfo;
-    }
-
-    private static ResolveInfo resolveInfo(ServiceInfo serviceInfo) {
-        ResolveInfo resolveInfo = new ResolveInfo();
-        resolveInfo.serviceInfo = serviceInfo;
-        return resolveInfo;
-    }
-
-    private static ServiceInfo serviceInfo(String packageName, String name, boolean isEnabled) {
-        ApplicationInfo applicationInfo = new ApplicationInfo();
-        applicationInfo.packageName = packageName;
-        applicationInfo.enabled = true;
-
-        ServiceInfo serviceInfo = new ServiceInfo();
-        serviceInfo.applicationInfo = applicationInfo;
-        serviceInfo.packageName = packageName;
-        serviceInfo.name = name;
-        serviceInfo.enabled = isEnabled;
-        return serviceInfo;
-    }
-
-    private static SystemService.TargetUser managedTargetUser(int ineligibleUserId) {
-        return new SystemService.TargetUser(managedUserInfo(ineligibleUserId));
-    }
-
-    private static SystemService.TargetUser eligibleTargetUser(int userId) {
-        return new SystemService.TargetUser(eligibleUserInfo(userId));
-    }
-
-    private static UserHandle userWithId(int userId) {
-        return argThat(userInfo -> userInfo.getIdentifier() == userId);
-    }
-
-    @Before
-    public void setUp() {
-        mMockingSession = mockitoSession()
-                .initMocks(this)
-                .startMocking();
-    }
-
-    @After
-    public void tearDown() {
-        mMockingSession.finishMocking();
-    }
-
-    @Test
-    public void testStartConnectionOnBootWithNoUser() {
-        GameServiceController gameServiceController =
-                new GameServiceController(mMockContext);
-
-        gameServiceController.onBootComplete();
-
-        verifyNoServiceBound();
-    }
-
-    @Test
-    public void testStartConnectionOnBootWithManagedUser() {
-        int userId = 12345;
-        GameServiceController gameServiceController =
-                new GameServiceController(mMockContext);
-
-        gameServiceController.notifyUserStarted(managedTargetUser(userId));
-        gameServiceController.onBootComplete();
-
-        verifyNoServiceBound();
-    }
-
-    @Test
-    public void testStartConnectionOnBootWithUserAndNoSystemGamesServiceSet() {
-        seedSystemGameServicePackageName("");
-
-        GameServiceController gameServiceController =
-                new GameServiceController(mMockContext);
-
-        gameServiceController.notifyUserStarted(eligibleTargetUser(1000));
-        gameServiceController.onBootComplete();
-
-        verifyNoServiceBound();
-    }
-
-    @Test
-    public void testStartConnectionOnBootWithUserAndSystemGamesServiceDoesNotExist() {
-        int userId = 12345;
-        String gameServicePackageName = "game.service.package";
-        seedSystemGameServicePackageName(gameServicePackageName);
-        seedGameServiceResolveInfos(gameServicePackageName, userId, ImmutableList.of());
-
-        GameServiceController gameServiceController =
-                new GameServiceController(mMockContext);
-
-        gameServiceController.notifyUserStarted(eligibleTargetUser(userId));
-        gameServiceController.onBootComplete();
-
-        verifyNoServiceBound();
-    }
-
-    @Test
-    public void testStartConnectionOnBootWithUserAndSystemGamesServiceSet() {
-        int userId = 12345;
-        String gameServicePackageName = "game.service.package";
-        String gameServiceComponent = "game.service.package.example.GameService";
-        seedSystemGameServicePackageName(gameServicePackageName);
-        seedGameServiceResolveInfos(gameServicePackageName, userId, ImmutableList.of(
-                resolveInfo(serviceInfo(gameServicePackageName, gameServiceComponent, true))));
-
-        GameServiceController gameServiceController =
-                new GameServiceController(mMockContext);
-
-        gameServiceController.notifyUserStarted(eligibleTargetUser(userId));
-        gameServiceController.onBootComplete();
-
-        verifyServiceBoundForUserAndComponent(userId, gameServicePackageName, gameServiceComponent);
-    }
-
-    @Test
-    public void testStartConnectionOnBootWithUserAndSystemGamesServiceNotEnabled() {
-        int userId = 12345;
-        String gameServicePackageName = "game.service.package";
-        String gameServiceComponent = "game.service.package.example.GameService";
-        seedSystemGameServicePackageName(gameServicePackageName);
-        seedGameServiceResolveInfos(gameServicePackageName, userId, ImmutableList.of(
-                resolveInfo(serviceInfo(gameServicePackageName, gameServiceComponent, false))));
-
-        GameServiceController gameServiceController =
-                new GameServiceController(mMockContext);
-
-        gameServiceController.notifyUserStarted(eligibleTargetUser(userId));
-        gameServiceController.onBootComplete();
-
-        verifyNoServiceBound();
-    }
-
-    @Test
-    public void testStartConnectionOnBootWithUserAndSystemGamesServiceHasMultipleComponents() {
-        int userId = 12345;
-        String gameServicePackageName = "game.service.package";
-        String gameServiceComponent1 = "game.service.package.example.GameService1";
-        String gameServiceComponent2 = "game.service.package.example.GameService2";
-        seedSystemGameServicePackageName(gameServicePackageName);
-        seedGameServiceResolveInfos(gameServicePackageName, userId, ImmutableList.of(
-                resolveInfo(serviceInfo(gameServicePackageName, gameServiceComponent1, true)),
-                resolveInfo(serviceInfo(gameServicePackageName, gameServiceComponent2, true))));
-
-        GameServiceController gameServiceController =
-                new GameServiceController(mMockContext);
-
-        gameServiceController.notifyUserStarted(eligibleTargetUser(userId));
-        gameServiceController.onBootComplete();
-
-        verifyServiceBoundForUserAndComponent(userId, gameServicePackageName,
-                gameServiceComponent1);
-    }
-
-    @Test
-    public void testStartConnectionOnBootWithUserAndSystemGamesServiceHasDisabledComponent() {
-        int userId = 12345;
-        String gameServicePackageName = "game.service.package";
-        String gameServiceComponent1 = "game.service.package.example.GameService1";
-        String gameServiceComponent2 = "game.service.package.example.GameService2";
-        seedSystemGameServicePackageName(gameServicePackageName);
-        seedGameServiceResolveInfos(gameServicePackageName, userId, ImmutableList.of(
-                resolveInfo(serviceInfo(gameServicePackageName, gameServiceComponent1, false)),
-                resolveInfo(serviceInfo(gameServicePackageName, gameServiceComponent2, true))));
-
-        GameServiceController gameServiceController =
-                new GameServiceController(mMockContext);
-
-        gameServiceController.notifyUserStarted(eligibleTargetUser(userId));
-        gameServiceController.onBootComplete();
-
-        verifyServiceBoundForUserAndComponent(userId, gameServicePackageName,
-                gameServiceComponent2);
-    }
-
-    @Test
-    public void testSwitchFromEligibleUserToEligibleUser() {
-        int userId1 = 1;
-        int userId2 = 2;
-        String gameServicePackageName = "game.service.package";
-        String gameServiceComponent = "game.service.package.example.GameService";
-        seedSystemGameServicePackageName(gameServicePackageName);
-        seedGameServiceResolveInfos(gameServicePackageName, userId1, ImmutableList.of(
-                resolveInfo(serviceInfo(gameServicePackageName, gameServiceComponent, true))));
-        seedGameServiceResolveInfos(gameServicePackageName, userId2, ImmutableList.of(
-                resolveInfo(serviceInfo(gameServicePackageName, gameServiceComponent, true))));
-        seedGameServiceToBindSuccessfully();
-
-        GameServiceController gameServiceController = new GameServiceController(mMockContext);
-
-        gameServiceController.onBootComplete();
-        gameServiceController.notifyUserStarted(eligibleTargetUser(userId1));
-
-        verifyServiceBoundForUserAndComponent(userId1, gameServicePackageName,
-                gameServiceComponent);
-
-        gameServiceController.notifyNewForegroundUser(eligibleTargetUser(userId2));
-
-        verify(mMockContext).unbindService(any());
-        verifyServiceBoundForUserAndComponent(userId2, gameServicePackageName,
-                gameServiceComponent);
-    }
-
-    @Test
-    public void testSwitchFromEligibleUserToIneligibleUser() {
-        int eligibleUserId = 1;
-        int ineligibleUserId = 2;
-        String gameServicePackageName = "game.service.package";
-        String gameServiceComponent = "game.service.package.example.GameService";
-        seedSystemGameServicePackageName(gameServicePackageName);
-        seedGameServiceResolveInfos(gameServicePackageName, eligibleUserId, ImmutableList.of(
-                resolveInfo(serviceInfo(gameServicePackageName, gameServiceComponent, true))));
-        seedGameServiceToBindSuccessfully();
-
-        GameServiceController gameServiceController =
-                new GameServiceController(mMockContext);
-
-        gameServiceController.onBootComplete();
-        gameServiceController.notifyUserStarted(eligibleTargetUser(eligibleUserId));
-
-        verifyServiceBoundForUserAndComponent(eligibleUserId, gameServicePackageName,
-                gameServiceComponent);
-
-        gameServiceController.notifyNewForegroundUser(managedTargetUser(ineligibleUserId));
-
-        verify(mMockContext).unbindService(any());
-    }
-
-    @Test
-    public void testSwitchFromIneligibleUserToEligibleUser() {
-        int eligibleUserId = 1;
-        int ineligibleUserId = 2;
-        String gameServicePackageName = "game.service.package";
-        String gameServiceComponent = "game.service.package.example.GameService";
-        seedSystemGameServicePackageName(gameServicePackageName);
-        seedGameServiceResolveInfos(gameServicePackageName, eligibleUserId, ImmutableList.of(
-                resolveInfo(serviceInfo(gameServicePackageName, gameServiceComponent, true))));
-        seedGameServiceToBindSuccessfully();
-
-        GameServiceController gameServiceController = new GameServiceController(mMockContext);
-
-        gameServiceController.onBootComplete();
-        gameServiceController.notifyUserStarted(managedTargetUser(ineligibleUserId));
-
-        verifyNoServiceBound();
-
-        gameServiceController.notifyNewForegroundUser(eligibleTargetUser(eligibleUserId));
-
-        verifyServiceBoundForUserAndComponent(eligibleUserId, gameServicePackageName,
-                gameServiceComponent);
-    }
-
-    @Test
-    public void testMultipleRunningUsers() {
-        int userId1 = 123;
-        int userId2 = 456;
-        String gameServicePackageName = "game.service.package";
-        String gameServiceComponent = "game.service.package.example.GameService";
-        seedSystemGameServicePackageName(gameServicePackageName);
-        seedGameServiceResolveInfos(gameServicePackageName, userId1, ImmutableList.of(
-                resolveInfo(serviceInfo(gameServicePackageName, gameServiceComponent, true))));
-        seedGameServiceToBindSuccessfully();
-
-        GameServiceController gameServiceController =
-                new GameServiceController(mMockContext);
-
-        gameServiceController.onBootComplete();
-        gameServiceController.notifyUserStarted(eligibleTargetUser(userId1));
-        gameServiceController.notifyUserStarted(eligibleTargetUser(userId2));
-
-        verifyServiceBoundForUserAndComponent(userId1, gameServicePackageName,
-                gameServiceComponent);
-        verifyServiceNotBoundForUser(userId2);
-        verify(mMockContext, never()).unbindService(any());
-    }
-
-    @Test
-    public void testForegroundUserStopped() {
-        int userId = 123123;
-        String gameServicePackageName = "game.service.package";
-        String gameServiceComponent = "game.service.package.example.GameService";
-        seedSystemGameServicePackageName(gameServicePackageName);
-        seedGameServiceResolveInfos(gameServicePackageName, userId, ImmutableList.of(
-                resolveInfo(serviceInfo(gameServicePackageName, gameServiceComponent, true))));
-        seedGameServiceToBindSuccessfully();
-
-        GameServiceController gameServiceController =
-                new GameServiceController(mMockContext);
-
-        gameServiceController.onBootComplete();
-        gameServiceController.notifyUserStarted(eligibleTargetUser(userId));
-
-        verifyServiceBoundForUserAndComponent(userId, gameServicePackageName, gameServiceComponent);
-
-        gameServiceController.notifyUserStopped(eligibleTargetUser(userId));
-
-        verify(mMockContext).unbindService(any());
-    }
-
-    @Test
-    public void testNonForegroundUserStopped() {
-        int userId1 = 123;
-        int userId2 = 456;
-        String gameServicePackageName = "game.service.package";
-        String gameServiceComponent = "game.service.package.example.GameService";
-        seedSystemGameServicePackageName(gameServicePackageName);
-        seedGameServiceResolveInfos(gameServicePackageName, userId1, ImmutableList.of(
-                resolveInfo(serviceInfo(gameServicePackageName, gameServiceComponent, true))));
-        seedGameServiceResolveInfos(gameServicePackageName, userId2, ImmutableList.of(
-                resolveInfo(serviceInfo(gameServicePackageName, gameServiceComponent, true))));
-        seedGameServiceToBindSuccessfully();
-
-        GameServiceController gameServiceController =
-                new GameServiceController(mMockContext);
-        InOrder inOrder = Mockito.inOrder(mMockContext);
-
-        gameServiceController.onBootComplete();
-        gameServiceController.notifyUserStarted(eligibleTargetUser(userId1));
-
-        inOrder.verify(mMockContext).bindServiceAsUser(any(), any(), anyInt(), userWithId(userId1));
-
-        gameServiceController.notifyNewForegroundUser(eligibleTargetUser(userId2));
-
-        inOrder.verify(mMockContext).unbindService(any());
-        inOrder.verify(mMockContext).bindServiceAsUser(any(), any(), anyInt(), userWithId(userId2));
-
-        gameServiceController.notifyUserStopped(eligibleTargetUser(userId1));
-
-        inOrder.verify(mMockContext, never()).unbindService(any());
-    }
-
-    private void seedSystemGameServicePackageName(String gameServicePackageName) {
-        when(mMockContext.getResources()).thenReturn(mMockResources);
-        when(mMockResources.getString(com.android.internal.R.string.config_systemGameService))
-                .thenReturn(gameServicePackageName);
-    }
-
-    private void seedGameServiceResolveInfos(String gameServicePackageName, int userId,
-            List<ResolveInfo> resolveInfos) {
-        when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);
-        doReturn(resolveInfos)
-                .when(mMockPackageManager).queryIntentServicesAsUser(
-                argThat(intent ->
-                        intent != null
-                                && intent.getAction().equals(GameService.SERVICE_INTERFACE)
-                                && intent.getPackage().equals(gameServicePackageName)
-                ),
-                eq(PackageManager.MATCH_SYSTEM_ONLY),
-                eq(userId));
-    }
-
-    private void seedGameServiceToBindSuccessfully() {
-        when(mMockContext.bindServiceAsUser(any(), any(), anyInt(), any())).thenReturn(true);
-    }
-
-    private void verifyNoServiceBound() {
-        verify(mMockContext, never()).bindServiceAsUser(any(), any(), anyInt(), any());
-    }
-
-    private void verifyServiceBoundForUserAndComponent(int userId, String gameServicePackageName,
-            String gameServiceComponent) {
-        verify(mMockContext).bindServiceAsUser(
-                argThat(intent -> intent.getAction().equals(GameService.SERVICE_INTERFACE)
-                        && intent.getComponent().getPackageName().equals(gameServicePackageName)
-                        && intent.getComponent().getClassName().equals(gameServiceComponent)),
-                any(),
-                anyInt(), argThat(userInfo -> userInfo.getIdentifier() == userId));
-    }
-
-    private void verifyServiceNotBoundForUser(int userId) {
-        verify(mMockContext, never()).bindServiceAsUser(
-                any(),
-                any(),
-                anyInt(), userWithId(userId));
-    }
-}
diff --git a/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java b/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java
new file mode 100644
index 0000000..b6c706e
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java
@@ -0,0 +1,560 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.app;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.inOrder;
+
+import android.annotation.Nullable;
+import android.app.IActivityTaskManager;
+import android.app.ITaskStackListener;
+import android.content.ComponentName;
+import android.content.pm.PackageManager;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.platform.test.annotations.Presubmit;
+import android.service.games.CreateGameSessionRequest;
+import android.service.games.IGameService;
+import android.service.games.IGameSession;
+import android.service.games.IGameSessionService;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.infra.AndroidFuture;
+import com.android.internal.util.ConcurrentUtils;
+import com.android.internal.util.FunctionalUtils.ThrowingConsumer;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
+
+import java.util.ArrayList;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Supplier;
+
+
+/**
+ * Unit tests for the {@link GameServiceProviderInstanceImpl}.
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@Presubmit
+public final class GameServiceProviderInstanceImplTest {
+
+    private static final int USER_ID = 10;
+    private static final String APP_A_PACKAGE = "com.package.app.a";
+    private static final ComponentName APP_A_MAIN_ACTIVITY =
+            new ComponentName(APP_A_PACKAGE, "com.package.app.a.MainActivity");
+
+    private static final String GAME_A_PACKAGE = "com.package.game.a";
+    private static final ComponentName GAME_A_MAIN_ACTIVITY =
+            new ComponentName(GAME_A_PACKAGE, "com.package.game.a.MainActivity");
+
+    private MockitoSession mMockingSession;
+    private GameServiceProviderInstance mGameServiceProviderInstance;
+    @Mock
+    private IActivityTaskManager mMockActivityTaskManager;
+    @Mock
+    private IGameService mMockGameService;
+    @Mock
+    private IGameSessionService mMockGameSessionService;
+    private FakeGameClassifier mFakeGameClassifier;
+    private FakeServiceConnector<IGameService> mFakeGameServiceConnector;
+    private FakeServiceConnector<IGameSessionService> mFakeGameSessionServiceConnector;
+    private ArrayList<ITaskStackListener> mTaskStackListeners;
+    private InOrder mInOrder;
+
+    @Before
+    public void setUp() throws PackageManager.NameNotFoundException, RemoteException {
+        mMockingSession = mockitoSession()
+                .initMocks(this)
+                .strictness(Strictness.LENIENT)
+                .startMocking();
+
+        mInOrder = inOrder(mMockGameService, mMockGameSessionService);
+
+        mFakeGameClassifier = new FakeGameClassifier();
+        mFakeGameClassifier.recordGamePackage(GAME_A_PACKAGE);
+
+        mFakeGameServiceConnector = new FakeServiceConnector<>(mMockGameService);
+        mFakeGameSessionServiceConnector = new FakeServiceConnector<>(mMockGameSessionService);
+
+        mTaskStackListeners = new ArrayList<>();
+        doAnswer(invocation -> {
+            mTaskStackListeners.add(invocation.getArgument(0));
+            return null;
+        }).when(mMockActivityTaskManager).registerTaskStackListener(any());
+
+        doAnswer(invocation -> {
+            mTaskStackListeners.remove(invocation.getArgument(0));
+            return null;
+        }).when(mMockActivityTaskManager).unregisterTaskStackListener(any());
+
+        mGameServiceProviderInstance = new GameServiceProviderInstanceImpl(
+                new UserHandle(USER_ID),
+                ConcurrentUtils.DIRECT_EXECUTOR,
+                mFakeGameClassifier,
+                mMockActivityTaskManager,
+                mFakeGameServiceConnector,
+                mFakeGameSessionServiceConnector);
+    }
+
+    @After
+    public void tearDown() {
+        mMockingSession.finishMocking();
+    }
+
+    @Test
+    public void start_startsGameSession() throws Exception {
+        mGameServiceProviderInstance.start();
+
+        mInOrder.verify(mMockGameService).connected();
+        mInOrder.verifyNoMoreInteractions();
+        assertThat(mFakeGameServiceConnector.getIsConnected()).isTrue();
+        assertThat(mFakeGameServiceConnector.getConnectCount()).isEqualTo(1);
+        assertThat(mFakeGameSessionServiceConnector.getConnectCount()).isEqualTo(0);
+    }
+
+    @Test
+    public void start_multipleTimes_startsGameSessionOnce() throws Exception {
+        mGameServiceProviderInstance.start();
+
+        mInOrder.verify(mMockGameService).connected();
+        mInOrder.verifyNoMoreInteractions();
+        assertThat(mFakeGameServiceConnector.getIsConnected()).isTrue();
+        assertThat(mFakeGameServiceConnector.getConnectCount()).isEqualTo(1);
+        assertThat(mFakeGameSessionServiceConnector.getConnectCount()).isEqualTo(0);
+    }
+
+    @Test
+    public void stop_neverStarted_doesNothing() throws Exception {
+        mGameServiceProviderInstance.stop();
+
+        assertThat(mFakeGameServiceConnector.getConnectCount()).isEqualTo(0);
+        assertThat(mFakeGameSessionServiceConnector.getConnectCount()).isEqualTo(0);
+        mInOrder.verifyNoMoreInteractions();
+    }
+
+    @Test
+    public void startAndStop_startsAndStopsGameSession() throws Exception {
+        mGameServiceProviderInstance.start();
+        mGameServiceProviderInstance.stop();
+
+        mInOrder.verify(mMockGameService).connected();
+        mInOrder.verify(mMockGameService).disconnected();
+        mInOrder.verifyNoMoreInteractions();
+        assertThat(mFakeGameServiceConnector.getIsConnected()).isFalse();
+        assertThat(mFakeGameServiceConnector.getConnectCount()).isEqualTo(1);
+        assertThat(mFakeGameSessionServiceConnector.getConnectCount()).isEqualTo(0);
+    }
+
+    @Test
+    public void startAndStop_multipleTimes_startsAndStopsGameSessionMultipleTimes()
+            throws Exception {
+        mGameServiceProviderInstance.start();
+        mGameServiceProviderInstance.stop();
+        mGameServiceProviderInstance.start();
+        mGameServiceProviderInstance.stop();
+
+        mInOrder.verify(mMockGameService).connected();
+        mInOrder.verify(mMockGameService).disconnected();
+        mInOrder.verify(mMockGameService).connected();
+        mInOrder.verify(mMockGameService).disconnected();
+        mInOrder.verifyNoMoreInteractions();
+        assertThat(mFakeGameServiceConnector.getIsConnected()).isFalse();
+        assertThat(mFakeGameServiceConnector.getConnectCount()).isEqualTo(2);
+        assertThat(mFakeGameSessionServiceConnector.getConnectCount()).isEqualTo(0);
+    }
+
+    @Test
+    public void stop_stopMultipleTimes_stopsGameSessionOnce() throws Exception {
+        mGameServiceProviderInstance.start();
+        mGameServiceProviderInstance.stop();
+        mGameServiceProviderInstance.stop();
+
+        mInOrder.verify(mMockGameService).connected();
+        mInOrder.verify(mMockGameService).disconnected();
+        mInOrder.verifyNoMoreInteractions();
+        assertThat(mFakeGameServiceConnector.getIsConnected()).isFalse();
+        assertThat(mFakeGameServiceConnector.getConnectCount()).isEqualTo(1);
+        assertThat(mFakeGameSessionServiceConnector.getConnectCount()).isEqualTo(0);
+    }
+
+    @Test
+    public void gameTaskStarted_neverStarted_doesNothing() throws Exception {
+        dispatchTaskCreated(10, GAME_A_MAIN_ACTIVITY);
+
+        mInOrder.verifyNoMoreInteractions();
+        assertThat(mFakeGameServiceConnector.getConnectCount()).isEqualTo(0);
+        assertThat(mFakeGameSessionServiceConnector.getConnectCount()).isEqualTo(0);
+    }
+
+    @Test
+    public void gameTaskRemoved_neverStarted_doesNothing() throws Exception {
+        dispatchTaskRemoved(10);
+
+        mInOrder.verifyNoMoreInteractions();
+        assertThat(mFakeGameServiceConnector.getConnectCount()).isEqualTo(0);
+        assertThat(mFakeGameSessionServiceConnector.getConnectCount()).isEqualTo(0);
+    }
+
+    @Test
+    public void gameTaskStarted_afterStopped_doesNothing() throws Exception {
+        mGameServiceProviderInstance.start();
+        mGameServiceProviderInstance.stop();
+        dispatchTaskCreated(10, GAME_A_MAIN_ACTIVITY);
+
+        mInOrder.verify(mMockGameService).connected();
+        mInOrder.verify(mMockGameService).disconnected();
+        mInOrder.verifyNoMoreInteractions();
+        assertThat(mFakeGameServiceConnector.getIsConnected()).isFalse();
+        assertThat(mFakeGameServiceConnector.getConnectCount()).isEqualTo(1);
+        assertThat(mFakeGameSessionServiceConnector.getConnectCount()).isEqualTo(0);
+    }
+
+    @Test
+    public void appTaskStarted_doesNothing() throws Exception {
+        mGameServiceProviderInstance.start();
+        dispatchTaskCreated(10, APP_A_MAIN_ACTIVITY);
+
+        mInOrder.verify(mMockGameService).connected();
+        mInOrder.verifyNoMoreInteractions();
+        assertThat(mFakeGameServiceConnector.getIsConnected()).isTrue();
+        assertThat(mFakeGameServiceConnector.getConnectCount()).isEqualTo(1);
+        assertThat(mFakeGameSessionServiceConnector.getConnectCount()).isEqualTo(0);
+    }
+
+    @Test
+    public void taskStarted_nullComponentName_ignoresAndDoesNotCrash() throws Exception {
+        mGameServiceProviderInstance.start();
+        dispatchTaskCreated(10, null);
+
+        mInOrder.verify(mMockGameService).connected();
+        mInOrder.verifyNoMoreInteractions();
+        assertThat(mFakeGameServiceConnector.getIsConnected()).isTrue();
+        assertThat(mFakeGameServiceConnector.getConnectCount()).isEqualTo(1);
+        assertThat(mFakeGameSessionServiceConnector.getConnectCount()).isEqualTo(0);
+    }
+
+    @Test
+    public void gameTaskStarted_createsGameSession() throws Exception {
+        CreateGameSessionRequest createGameSessionRequest =
+                new CreateGameSessionRequest(10, GAME_A_PACKAGE);
+        Supplier<AndroidFuture<IBinder>> gameSession10Future =
+                captureCreateGameSessionFuture(createGameSessionRequest);
+
+        mGameServiceProviderInstance.start();
+        dispatchTaskCreated(10, GAME_A_MAIN_ACTIVITY);
+        IGameSessionStub gameSession10 = new IGameSessionStub();
+        gameSession10Future.get().complete(gameSession10);
+
+        mInOrder.verify(mMockGameService).connected();
+        mInOrder.verify(mMockGameSessionService).create(eq(createGameSessionRequest), any());
+        mInOrder.verifyNoMoreInteractions();
+        assertThat(gameSession10.mIsDestroyed).isFalse();
+        assertThat(mFakeGameServiceConnector.getIsConnected()).isTrue();
+        assertThat(mFakeGameServiceConnector.getConnectCount()).isEqualTo(1);
+        assertThat(mFakeGameSessionServiceConnector.getIsConnected()).isTrue();
+        assertThat(mFakeGameSessionServiceConnector.getConnectCount()).isEqualTo(1);
+    }
+
+    @Test
+    public void gameTaskRemoved_whileAwaitingGameSessionAttached_destroysGameSession()
+            throws Exception {
+        CreateGameSessionRequest createGameSessionRequest =
+                new CreateGameSessionRequest(10, GAME_A_PACKAGE);
+        Supplier<AndroidFuture<IBinder>> gameSession10Future =
+                captureCreateGameSessionFuture(createGameSessionRequest);
+
+        mGameServiceProviderInstance.start();
+        dispatchTaskCreated(10, GAME_A_MAIN_ACTIVITY);
+        dispatchTaskRemoved(10);
+        IGameSessionStub gameSession10 = new IGameSessionStub();
+        gameSession10Future.get().complete(gameSession10);
+
+        mInOrder.verify(mMockGameService).connected();
+        mInOrder.verify(mMockGameSessionService).create(eq(createGameSessionRequest), any());
+        mInOrder.verifyNoMoreInteractions();
+        assertThat(gameSession10.mIsDestroyed).isTrue();
+        assertThat(mFakeGameServiceConnector.getIsConnected()).isTrue();
+        assertThat(mFakeGameServiceConnector.getConnectCount()).isEqualTo(1);
+        assertThat(mFakeGameSessionServiceConnector.getIsConnected()).isFalse();
+        assertThat(mFakeGameSessionServiceConnector.getConnectCount()).isEqualTo(1);
+    }
+
+    @Test
+    public void gameTaskRemoved_destroysGameSession() throws Exception {
+        CreateGameSessionRequest createGameSessionRequest =
+                new CreateGameSessionRequest(10, GAME_A_PACKAGE);
+        Supplier<AndroidFuture<IBinder>> gameSession10Future =
+                captureCreateGameSessionFuture(createGameSessionRequest);
+
+        mGameServiceProviderInstance.start();
+        dispatchTaskCreated(10, GAME_A_MAIN_ACTIVITY);
+        IGameSessionStub gameSession10 = new IGameSessionStub();
+        gameSession10Future.get().complete(gameSession10);
+        dispatchTaskRemoved(10);
+
+        mInOrder.verify(mMockGameService).connected();
+        mInOrder.verify(mMockGameSessionService).create(eq(createGameSessionRequest), any());
+        mInOrder.verifyNoMoreInteractions();
+        assertThat(gameSession10.mIsDestroyed).isTrue();
+        assertThat(mFakeGameServiceConnector.getIsConnected()).isTrue();
+        assertThat(mFakeGameServiceConnector.getConnectCount()).isEqualTo(1);
+        assertThat(mFakeGameSessionServiceConnector.getIsConnected()).isFalse();
+        assertThat(mFakeGameSessionServiceConnector.getConnectCount()).isEqualTo(1);
+    }
+
+    @Test
+    public void gameTaskStarted_multipleTimes_createsMultipleGameSessions() throws Exception {
+        CreateGameSessionRequest createGameSessionRequest10 =
+                new CreateGameSessionRequest(10, GAME_A_PACKAGE);
+        Supplier<AndroidFuture<IBinder>> gameSession10Future =
+                captureCreateGameSessionFuture(createGameSessionRequest10);
+
+        CreateGameSessionRequest createGameSessionRequest11 =
+                new CreateGameSessionRequest(11, GAME_A_PACKAGE);
+        Supplier<AndroidFuture<IBinder>> gameSession11Future =
+                captureCreateGameSessionFuture(createGameSessionRequest11);
+
+        mGameServiceProviderInstance.start();
+        dispatchTaskCreated(10, GAME_A_MAIN_ACTIVITY);
+        IGameSessionStub gameSession10 = new IGameSessionStub();
+        gameSession10Future.get().complete(gameSession10);
+
+        dispatchTaskCreated(11, GAME_A_MAIN_ACTIVITY);
+        IGameSessionStub gameSession11 = new IGameSessionStub();
+        gameSession11Future.get().complete(gameSession11);
+
+        mInOrder.verify(mMockGameService).connected();
+        mInOrder.verify(mMockGameSessionService).create(eq(createGameSessionRequest10), any());
+        mInOrder.verify(mMockGameSessionService).create(eq(createGameSessionRequest11), any());
+        mInOrder.verifyNoMoreInteractions();
+        assertThat(gameSession10.mIsDestroyed).isFalse();
+        assertThat(gameSession11.mIsDestroyed).isFalse();
+        assertThat(mFakeGameServiceConnector.getIsConnected()).isTrue();
+        assertThat(mFakeGameServiceConnector.getConnectCount()).isEqualTo(1);
+        assertThat(mFakeGameSessionServiceConnector.getIsConnected()).isTrue();
+        assertThat(mFakeGameSessionServiceConnector.getConnectCount()).isEqualTo(1);
+    }
+
+    @Test
+    public void gameTaskRemoved_afterMultipleCreated_destroysOnlyThatGameSession()
+            throws Exception {
+        CreateGameSessionRequest createGameSessionRequest10 =
+                new CreateGameSessionRequest(10, GAME_A_PACKAGE);
+        Supplier<AndroidFuture<IBinder>> gameSession10Future =
+                captureCreateGameSessionFuture(createGameSessionRequest10);
+
+        CreateGameSessionRequest createGameSessionRequest11 =
+                new CreateGameSessionRequest(11, GAME_A_PACKAGE);
+        Supplier<AndroidFuture<IBinder>> gameSession11Future =
+                captureCreateGameSessionFuture(createGameSessionRequest11);
+
+        mGameServiceProviderInstance.start();
+        dispatchTaskCreated(10, GAME_A_MAIN_ACTIVITY);
+        IGameSessionStub gameSession10 = new IGameSessionStub();
+        gameSession10Future.get().complete(gameSession10);
+
+        dispatchTaskCreated(11, GAME_A_MAIN_ACTIVITY);
+        IGameSessionStub gameSession11 = new IGameSessionStub();
+        gameSession11Future.get().complete(gameSession11);
+
+        dispatchTaskRemoved(10);
+
+        mInOrder.verify(mMockGameService).connected();
+        mInOrder.verify(mMockGameSessionService).create(eq(createGameSessionRequest10), any());
+        mInOrder.verify(mMockGameSessionService).create(eq(createGameSessionRequest11), any());
+        mInOrder.verifyNoMoreInteractions();
+        assertThat(gameSession10.mIsDestroyed).isTrue();
+        assertThat(gameSession11.mIsDestroyed).isFalse();
+        assertThat(mFakeGameServiceConnector.getIsConnected()).isTrue();
+        assertThat(mFakeGameServiceConnector.getConnectCount()).isEqualTo(1);
+        assertThat(mFakeGameSessionServiceConnector.getIsConnected()).isTrue();
+        assertThat(mFakeGameSessionServiceConnector.getConnectCount()).isEqualTo(1);
+    }
+
+    @Test
+    public void allGameTasksRemoved_destroysAllGameSessions() throws Exception {
+        CreateGameSessionRequest createGameSessionRequest10 =
+                new CreateGameSessionRequest(10, GAME_A_PACKAGE);
+        Supplier<AndroidFuture<IBinder>> gameSession10Future =
+                captureCreateGameSessionFuture(createGameSessionRequest10);
+
+        CreateGameSessionRequest createGameSessionRequest11 =
+                new CreateGameSessionRequest(11, GAME_A_PACKAGE);
+        Supplier<AndroidFuture<IBinder>> gameSession11Future =
+                captureCreateGameSessionFuture(createGameSessionRequest11);
+
+        mGameServiceProviderInstance.start();
+        dispatchTaskCreated(10, GAME_A_MAIN_ACTIVITY);
+        IGameSessionStub gameSession10 = new IGameSessionStub();
+        gameSession10Future.get().complete(gameSession10);
+
+        dispatchTaskCreated(11, GAME_A_MAIN_ACTIVITY);
+        IGameSessionStub gameSession11 = new IGameSessionStub();
+        gameSession11Future.get().complete(gameSession11);
+
+        dispatchTaskRemoved(10);
+        dispatchTaskRemoved(11);
+
+        mInOrder.verify(mMockGameService).connected();
+        mInOrder.verify(mMockGameSessionService).create(eq(createGameSessionRequest10), any());
+        mInOrder.verify(mMockGameSessionService).create(eq(createGameSessionRequest11), any());
+        mInOrder.verifyNoMoreInteractions();
+        assertThat(gameSession10.mIsDestroyed).isTrue();
+        assertThat(gameSession11.mIsDestroyed).isTrue();
+        assertThat(mFakeGameServiceConnector.getIsConnected()).isTrue();
+        assertThat(mFakeGameServiceConnector.getConnectCount()).isEqualTo(1);
+        assertThat(mFakeGameSessionServiceConnector.getIsConnected()).isFalse();
+        assertThat(mFakeGameSessionServiceConnector.getConnectCount()).isEqualTo(1);
+    }
+
+    @Test
+    public void gameTasksCreated_afterAllPreviousSessionsDestroyed_createsSession()
+            throws Exception {
+        CreateGameSessionRequest createGameSessionRequest10 =
+                new CreateGameSessionRequest(10, GAME_A_PACKAGE);
+        Supplier<AndroidFuture<IBinder>> gameSession10Future =
+                captureCreateGameSessionFuture(createGameSessionRequest10);
+
+        CreateGameSessionRequest createGameSessionRequest11 =
+                new CreateGameSessionRequest(11, GAME_A_PACKAGE);
+        Supplier<AndroidFuture<IBinder>> gameSession11Future =
+                captureCreateGameSessionFuture(createGameSessionRequest11);
+
+        CreateGameSessionRequest createGameSessionRequest12 =
+                new CreateGameSessionRequest(12, GAME_A_PACKAGE);
+        Supplier<AndroidFuture<IBinder>> unusedGameSession12Future =
+                captureCreateGameSessionFuture(createGameSessionRequest12);
+
+        mGameServiceProviderInstance.start();
+        dispatchTaskCreated(10, GAME_A_MAIN_ACTIVITY);
+        IGameSessionStub gameSession10 = new IGameSessionStub();
+        gameSession10Future.get().complete(gameSession10);
+
+        dispatchTaskCreated(11, GAME_A_MAIN_ACTIVITY);
+        IGameSessionStub gameSession11 = new IGameSessionStub();
+        gameSession11Future.get().complete(gameSession11);
+
+        dispatchTaskRemoved(10);
+        dispatchTaskRemoved(11);
+
+        dispatchTaskCreated(12, GAME_A_MAIN_ACTIVITY);
+        IGameSessionStub gameSession12 = new IGameSessionStub();
+        gameSession11Future.get().complete(gameSession12);
+
+        mInOrder.verify(mMockGameService).connected();
+        mInOrder.verify(mMockGameSessionService).create(eq(createGameSessionRequest10), any());
+        mInOrder.verify(mMockGameSessionService).create(eq(createGameSessionRequest11), any());
+        mInOrder.verify(mMockGameSessionService).create(eq(createGameSessionRequest12), any());
+        mInOrder.verifyNoMoreInteractions();
+        assertThat(gameSession10.mIsDestroyed).isTrue();
+        assertThat(gameSession11.mIsDestroyed).isTrue();
+        assertThat(gameSession12.mIsDestroyed).isFalse();
+        assertThat(mFakeGameServiceConnector.getIsConnected()).isTrue();
+        assertThat(mFakeGameServiceConnector.getConnectCount()).isEqualTo(1);
+        assertThat(mFakeGameSessionServiceConnector.getIsConnected()).isTrue();
+        assertThat(mFakeGameSessionServiceConnector.getConnectCount()).isEqualTo(2);
+    }
+
+    @Test
+    public void stop_severalActiveGameSessions_destroysGameSessionsAndUnbinds() throws Exception {
+        CreateGameSessionRequest createGameSessionRequest10 =
+                new CreateGameSessionRequest(10, GAME_A_PACKAGE);
+        Supplier<AndroidFuture<IBinder>> gameSession10Future =
+                captureCreateGameSessionFuture(createGameSessionRequest10);
+
+        CreateGameSessionRequest createGameSessionRequest11 =
+                new CreateGameSessionRequest(11, GAME_A_PACKAGE);
+        Supplier<AndroidFuture<IBinder>> gameSession11Future =
+                captureCreateGameSessionFuture(createGameSessionRequest11);
+
+        mGameServiceProviderInstance.start();
+        dispatchTaskCreated(10, GAME_A_MAIN_ACTIVITY);
+        IGameSessionStub gameSession10 = new IGameSessionStub();
+        gameSession10Future.get().complete(gameSession10);
+        dispatchTaskCreated(11, GAME_A_MAIN_ACTIVITY);
+        IGameSessionStub gameSession11 = new IGameSessionStub();
+        gameSession11Future.get().complete(gameSession11);
+        mGameServiceProviderInstance.stop();
+
+        mInOrder.verify(mMockGameService).connected();
+        mInOrder.verify(mMockGameSessionService).create(eq(createGameSessionRequest10), any());
+        mInOrder.verify(mMockGameSessionService).create(eq(createGameSessionRequest11), any());
+        mInOrder.verify(mMockGameService).disconnected();
+        mInOrder.verifyNoMoreInteractions();
+        assertThat(gameSession10.mIsDestroyed).isTrue();
+        assertThat(gameSession11.mIsDestroyed).isTrue();
+        assertThat(mFakeGameServiceConnector.getIsConnected()).isFalse();
+        assertThat(mFakeGameServiceConnector.getConnectCount()).isEqualTo(1);
+        assertThat(mFakeGameSessionServiceConnector.getIsConnected()).isFalse();
+        assertThat(mFakeGameSessionServiceConnector.getConnectCount()).isEqualTo(1);
+    }
+
+    private Supplier<AndroidFuture<IBinder>> captureCreateGameSessionFuture(
+            CreateGameSessionRequest expectedCreateGameSessionRequest) throws Exception {
+        final AtomicReference<AndroidFuture<IBinder>> gameSessionFuture = new AtomicReference<>();
+        doAnswer(invocation -> {
+            gameSessionFuture.set(invocation.getArgument(1));
+            return null;
+        }).when(mMockGameSessionService).create(eq(expectedCreateGameSessionRequest), any());
+
+        return gameSessionFuture::get;
+    }
+
+    private void dispatchTaskRemoved(int taskId) {
+        dispatchTaskChangeEvent(taskStackListener -> {
+            taskStackListener.onTaskRemoved(taskId);
+        });
+    }
+
+    private void dispatchTaskCreated(int taskId, @Nullable ComponentName componentName) {
+        dispatchTaskChangeEvent(taskStackListener -> {
+            taskStackListener.onTaskCreated(taskId, componentName);
+        });
+    }
+
+    private void dispatchTaskChangeEvent(
+            ThrowingConsumer<ITaskStackListener> taskStackListenerConsumer) {
+        for (ITaskStackListener taskStackListener : mTaskStackListeners) {
+            taskStackListenerConsumer.accept(taskStackListener);
+        }
+    }
+
+    private static class IGameSessionStub extends IGameSession.Stub {
+        boolean mIsDestroyed = false;
+
+        @Override
+        public void destroy() {
+            mIsDestroyed = true;
+        }
+    }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderSelectorImplTest.java b/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderSelectorImplTest.java
new file mode 100644
index 0000000..59d0970
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderSelectorImplTest.java
@@ -0,0 +1,403 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.app;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.content.ComponentName;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.content.pm.UserInfo;
+import android.content.res.AssetManager;
+import android.content.res.Resources;
+import android.content.res.XmlResourceParser;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.platform.test.annotations.Presubmit;
+import android.service.games.GameService;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.SystemService;
+
+import com.google.common.collect.ImmutableList;
+
+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;
+
+
+/**
+ * Unit tests for the {@link GameServiceProviderSelectorImpl}.
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@Presubmit
+public final class GameServiceProviderSelectorImplTest {
+
+    private static final UserHandle USER_HANDLE_10 = new UserHandle(10);
+
+    private static final int GAME_SERVICE_META_DATA_RES_ID = 1337;
+    private static final String GAME_SERVICE_PACKAGE_NAME = "com.game.service.provider";
+    private static final String GAME_SERVICE_CLASS_NAME = "com.game.service.provider.GameService";
+    private static final ComponentName GAME_SERVICE_COMPONENT =
+            new ComponentName(GAME_SERVICE_PACKAGE_NAME, GAME_SERVICE_CLASS_NAME);
+
+    private static final int GAME_SERVICE_B_META_DATA_RES_ID = 1338;
+    private static final String GAME_SERVICE_B_CLASS_NAME =
+            "com.game.service.provider.GameServiceB";
+    private static final ComponentName GAME_SERVICE_B_COMPONENT =
+            new ComponentName(GAME_SERVICE_PACKAGE_NAME, GAME_SERVICE_B_CLASS_NAME);
+    private static final ServiceInfo GAME_SERVICE_B_WITH_OUT_META_DATA =
+            serviceInfo(GAME_SERVICE_PACKAGE_NAME, GAME_SERVICE_B_CLASS_NAME);
+    private static final ServiceInfo GAME_SERVICE_B_SERVICE_INFO =
+            addGameServiceMetaData(GAME_SERVICE_B_WITH_OUT_META_DATA,
+                    GAME_SERVICE_B_META_DATA_RES_ID);
+
+    private static final String GAME_SESSION_SERVICE_CLASS_NAME =
+            "com.game.service.provider.GameSessionService";
+    private static final ComponentName GAME_SESSION_SERVICE_COMPONENT =
+            new ComponentName(GAME_SERVICE_PACKAGE_NAME, GAME_SESSION_SERVICE_CLASS_NAME);
+    private static final ServiceInfo GAME_SERVICE_SERVICE_INFO_WITHOUT_META_DATA =
+            serviceInfo(GAME_SERVICE_PACKAGE_NAME, GAME_SERVICE_CLASS_NAME);
+    private static final ServiceInfo GAME_SERVICE_SERVICE_INFO =
+            addGameServiceMetaData(GAME_SERVICE_SERVICE_INFO_WITHOUT_META_DATA,
+                    GAME_SERVICE_META_DATA_RES_ID);
+
+    @Mock
+    private PackageManager mMockPackageManager;
+    private Resources mSpyResources;
+    private MockitoSession mMockingSession;
+    private GameServiceProviderSelector mGameServiceProviderSelector;
+
+    @Before
+    public void setUp() throws PackageManager.NameNotFoundException {
+        mMockingSession = mockitoSession()
+                .initMocks(this)
+                .strictness(Strictness.LENIENT)
+                .startMocking();
+
+        mSpyResources = spy(
+                InstrumentationRegistry.getInstrumentation().getContext().getResources());
+
+        when(mMockPackageManager.getResourcesForApplication(anyString()))
+                .thenReturn(mSpyResources);
+        mGameServiceProviderSelector = new GameServiceProviderSelectorImpl(
+                mSpyResources,
+                mMockPackageManager);
+    }
+
+    @After
+    public void tearDown() {
+        mMockingSession.finishMocking();
+    }
+
+    @Test
+    public void get_nullUser_returnsNull()
+            throws Exception {
+        seedSystemGameServicePackageName(GAME_SERVICE_PACKAGE_NAME);
+        seedGameServiceResolveInfos(GAME_SERVICE_PACKAGE_NAME, USER_HANDLE_10,
+                resolveInfo(GAME_SERVICE_SERVICE_INFO));
+        seedServiceServiceInfo(GAME_SESSION_SERVICE_COMPONENT);
+        seedGameServiceMetaDataFromFile(GAME_SERVICE_PACKAGE_NAME,
+                GAME_SERVICE_META_DATA_RES_ID,
+                "res/xml/game_service_metadata_valid.xml");
+
+        GameServiceProviderConfiguration gameServiceProviderConfiguration =
+                mGameServiceProviderSelector.get(null);
+
+        assertThat(gameServiceProviderConfiguration).isNull();
+    }
+
+    @Test
+    public void get_managedUser_returnsNull()
+            throws Exception {
+        seedSystemGameServicePackageName(GAME_SERVICE_PACKAGE_NAME);
+        seedGameServiceResolveInfos(GAME_SERVICE_PACKAGE_NAME, USER_HANDLE_10,
+                resolveInfo(GAME_SERVICE_SERVICE_INFO));
+        seedServiceServiceInfo(GAME_SESSION_SERVICE_COMPONENT);
+        seedGameServiceMetaDataFromFile(GAME_SERVICE_PACKAGE_NAME,
+                GAME_SERVICE_META_DATA_RES_ID,
+                "res/xml/game_service_metadata_valid.xml");
+
+        GameServiceProviderConfiguration gameServiceProviderConfiguration =
+                mGameServiceProviderSelector.get(managedTargetUser(USER_HANDLE_10));
+
+        assertThat(gameServiceProviderConfiguration).isNull();
+    }
+
+    @Test
+    public void get_noSystemGameService_returnsNull()
+            throws Exception {
+        seedGameServiceResolveInfos(GAME_SERVICE_PACKAGE_NAME, USER_HANDLE_10,
+                resolveInfo(GAME_SERVICE_SERVICE_INFO));
+        seedServiceServiceInfo(GAME_SESSION_SERVICE_COMPONENT);
+        seedGameServiceMetaDataFromFile(GAME_SERVICE_PACKAGE_NAME,
+                GAME_SERVICE_META_DATA_RES_ID,
+                "res/xml/game_service_metadata_valid.xml");
+
+        GameServiceProviderConfiguration gameServiceProviderConfiguration =
+                mGameServiceProviderSelector.get(eligibleTargetUser(USER_HANDLE_10));
+
+        assertThat(gameServiceProviderConfiguration).isNull();
+    }
+
+    @Test
+    public void get_noGameServiceProvidersAvailable_returnsNull()
+            throws Exception {
+        seedSystemGameServicePackageName(GAME_SERVICE_PACKAGE_NAME);
+        seedGameServiceResolveInfos(GAME_SERVICE_PACKAGE_NAME, USER_HANDLE_10);
+        seedServiceServiceInfo(GAME_SESSION_SERVICE_COMPONENT);
+        seedGameServiceMetaDataFromFile(GAME_SERVICE_PACKAGE_NAME,
+                GAME_SERVICE_META_DATA_RES_ID,
+                "res/xml/game_service_metadata_valid.xml");
+
+        GameServiceProviderConfiguration gameServiceProviderConfiguration =
+                mGameServiceProviderSelector.get(eligibleTargetUser(USER_HANDLE_10));
+
+        assertThat(gameServiceProviderConfiguration).isNull();
+    }
+
+    @Test
+    public void get_gameServiceProviderHasNoMetaData_returnsNull()
+            throws Exception {
+        seedSystemGameServicePackageName(GAME_SERVICE_PACKAGE_NAME);
+        seedGameServiceResolveInfos(GAME_SERVICE_PACKAGE_NAME, USER_HANDLE_10,
+                resolveInfo(GAME_SERVICE_SERVICE_INFO_WITHOUT_META_DATA));
+        seedServiceServiceInfo(GAME_SESSION_SERVICE_COMPONENT);
+
+        GameServiceProviderConfiguration gameServiceProviderConfiguration =
+                mGameServiceProviderSelector.get(eligibleTargetUser(USER_HANDLE_10));
+
+        assertThat(gameServiceProviderConfiguration).isNull();
+    }
+
+    @Test
+    public void get_gameSessionServiceDoesNotExist_returnsNull()
+            throws Exception {
+        seedSystemGameServicePackageName(GAME_SERVICE_PACKAGE_NAME);
+        seedGameServiceResolveInfos(GAME_SERVICE_PACKAGE_NAME, USER_HANDLE_10,
+                resolveInfo(GAME_SERVICE_SERVICE_INFO));
+        seedServiceServiceInfoNotFound(GAME_SESSION_SERVICE_COMPONENT);
+        seedGameServiceMetaDataFromFile(GAME_SERVICE_PACKAGE_NAME,
+                GAME_SERVICE_META_DATA_RES_ID,
+                "res/xml/game_service_metadata_valid.xml");
+
+        GameServiceProviderConfiguration gameServiceProviderConfiguration =
+                mGameServiceProviderSelector.get(eligibleTargetUser(USER_HANDLE_10));
+
+        assertThat(gameServiceProviderConfiguration).isNull();
+    }
+
+    @Test
+    public void get_metaDataWrongFirstTag_returnsNull() throws Exception {
+        seedSystemGameServicePackageName(GAME_SERVICE_PACKAGE_NAME);
+        seedGameServiceResolveInfos(GAME_SERVICE_PACKAGE_NAME, USER_HANDLE_10,
+                resolveInfo(GAME_SERVICE_SERVICE_INFO));
+        seedServiceServiceInfo(GAME_SESSION_SERVICE_COMPONENT);
+        seedGameServiceMetaDataFromFile(GAME_SERVICE_PACKAGE_NAME,
+                GAME_SERVICE_META_DATA_RES_ID,
+                "res/xml/game_service_metadata_wrong_first_tag.xml");
+
+        GameServiceProviderConfiguration gameServiceProviderConfiguration =
+                mGameServiceProviderSelector.get(eligibleTargetUser(USER_HANDLE_10));
+
+        assertThat(gameServiceProviderConfiguration).isNull();
+    }
+
+    @Test
+    public void get_validGameServiceProviderAvailable_returnsGameServiceProvider()
+            throws Exception {
+        seedSystemGameServicePackageName(GAME_SERVICE_PACKAGE_NAME);
+        seedGameServiceResolveInfos(GAME_SERVICE_PACKAGE_NAME, USER_HANDLE_10,
+                resolveInfo(GAME_SERVICE_SERVICE_INFO));
+        seedServiceServiceInfo(GAME_SESSION_SERVICE_COMPONENT);
+        seedGameServiceMetaDataFromFile(GAME_SERVICE_PACKAGE_NAME,
+                GAME_SERVICE_META_DATA_RES_ID,
+                "res/xml/game_service_metadata_valid.xml");
+
+        GameServiceProviderConfiguration gameServiceProviderConfiguration =
+                mGameServiceProviderSelector.get(eligibleTargetUser(USER_HANDLE_10));
+
+        GameServiceProviderConfiguration expectedGameServiceProviderConfiguration =
+                new GameServiceProviderConfiguration(USER_HANDLE_10,
+                        GAME_SERVICE_COMPONENT,
+                        GAME_SESSION_SERVICE_COMPONENT);
+        assertThat(gameServiceProviderConfiguration).isEqualTo(
+                expectedGameServiceProviderConfiguration);
+    }
+
+    @Test
+    public void get_multipleGameServiceProvidersAllValid_returnsFirstValidGameServiceProvider()
+            throws Exception {
+        seedSystemGameServicePackageName(GAME_SERVICE_PACKAGE_NAME);
+
+        seedGameServiceResolveInfos(GAME_SERVICE_PACKAGE_NAME, USER_HANDLE_10,
+                resolveInfo(GAME_SERVICE_B_SERVICE_INFO), resolveInfo(GAME_SERVICE_SERVICE_INFO));
+        seedServiceServiceInfo(GAME_SESSION_SERVICE_COMPONENT);
+        seedGameServiceMetaDataFromFile(GAME_SERVICE_PACKAGE_NAME,
+                GAME_SERVICE_B_META_DATA_RES_ID,
+                "res/xml/game_service_metadata_valid.xml");
+        seedGameServiceMetaDataFromFile(GAME_SERVICE_PACKAGE_NAME,
+                GAME_SERVICE_META_DATA_RES_ID,
+                "res/xml/game_service_metadata_valid.xml");
+
+        GameServiceProviderConfiguration gameServiceProviderConfiguration =
+                mGameServiceProviderSelector.get(eligibleTargetUser(USER_HANDLE_10));
+
+        GameServiceProviderConfiguration expectedGameServiceProviderConfiguration =
+                new GameServiceProviderConfiguration(USER_HANDLE_10,
+                        GAME_SERVICE_B_COMPONENT,
+                        GAME_SESSION_SERVICE_COMPONENT);
+        assertThat(gameServiceProviderConfiguration).isEqualTo(
+                expectedGameServiceProviderConfiguration);
+    }
+
+    @Test
+    public void get_multipleGameServiceProvidersSomeInvalid_returnsFirstValidGameServiceProvider()
+            throws Exception {
+        seedSystemGameServicePackageName(GAME_SERVICE_PACKAGE_NAME);
+
+        seedGameServiceResolveInfos(GAME_SERVICE_PACKAGE_NAME, USER_HANDLE_10,
+                resolveInfo(GAME_SERVICE_B_SERVICE_INFO), resolveInfo(GAME_SERVICE_SERVICE_INFO));
+        seedServiceServiceInfo(GAME_SESSION_SERVICE_COMPONENT);
+        seedGameServiceMetaDataFromFile(GAME_SERVICE_PACKAGE_NAME,
+                GAME_SERVICE_META_DATA_RES_ID,
+                "res/xml/game_service_metadata_valid.xml");
+
+        GameServiceProviderConfiguration gameServiceProviderConfiguration =
+                mGameServiceProviderSelector.get(eligibleTargetUser(USER_HANDLE_10));
+
+        GameServiceProviderConfiguration expectedGameServiceProviderConfiguration =
+                new GameServiceProviderConfiguration(USER_HANDLE_10,
+                        GAME_SERVICE_COMPONENT,
+                        GAME_SESSION_SERVICE_COMPONENT);
+        assertThat(gameServiceProviderConfiguration).isEqualTo(
+                expectedGameServiceProviderConfiguration);
+    }
+
+    private void seedSystemGameServicePackageName(String gameServicePackageName) {
+        when(mSpyResources.getString(com.android.internal.R.string.config_systemGameService))
+                .thenReturn(gameServicePackageName);
+    }
+
+    private void seedGameServiceResolveInfos(
+            String gameServicePackageName,
+            UserHandle userHandle,
+            ResolveInfo... resolveInfos) {
+        doReturn(ImmutableList.copyOf(resolveInfos))
+                .when(mMockPackageManager).queryIntentServicesAsUser(
+                        argThat(intent ->
+                                intent != null
+                                        && intent.getAction().equals(
+                                                GameService.ACTION_GAME_SERVICE)
+                                        && intent.getPackage().equals(gameServicePackageName)
+                        ),
+                        anyInt(),
+                        eq(userHandle.getIdentifier()));
+    }
+
+    private void seedServiceServiceInfo(ComponentName componentName) throws Exception {
+        when(mMockPackageManager.getServiceInfo(eq(componentName), anyInt()))
+                .thenReturn(
+                        serviceInfo(componentName.getPackageName(), componentName.getClassName()));
+    }
+
+    private void seedServiceServiceInfoNotFound(ComponentName componentName) throws Exception {
+        when(mMockPackageManager.getServiceInfo(eq(componentName), anyInt()))
+                .thenThrow(new PackageManager.NameNotFoundException());
+    }
+
+    private void seedGameServiceMetaDataFromFile(String packageName, int resId, String fileName)
+            throws Exception {
+
+        AssetManager assetManager =
+                InstrumentationRegistry.getInstrumentation().getContext().getAssets();
+        XmlResourceParser xmlResourceParser =
+                assetManager.openXmlResourceParser(fileName);
+
+        when(mMockPackageManager.getXml(eq(packageName), eq(resId), any()))
+                .thenReturn(xmlResourceParser);
+    }
+
+    private static UserInfo eligibleUserInfo(int uid) {
+        return new UserInfo(uid, "", "", UserInfo.FLAG_FULL);
+    }
+
+    private static UserInfo managedUserInfo(int uid) {
+        UserInfo userInfo = eligibleUserInfo(uid);
+        userInfo.userType = UserManager.USER_TYPE_PROFILE_MANAGED;
+        return userInfo;
+    }
+
+    private static ResolveInfo resolveInfo(ServiceInfo serviceInfo) {
+        ResolveInfo resolveInfo = new ResolveInfo();
+        resolveInfo.serviceInfo = serviceInfo;
+        return resolveInfo;
+    }
+
+    private static ServiceInfo serviceInfo(String packageName, String name) {
+        ApplicationInfo applicationInfo = new ApplicationInfo();
+        applicationInfo.packageName = packageName;
+        applicationInfo.enabled = true;
+
+        ServiceInfo serviceInfo = new ServiceInfo();
+        serviceInfo.applicationInfo = applicationInfo;
+        serviceInfo.packageName = packageName;
+        serviceInfo.name = name;
+        serviceInfo.enabled = true;
+
+        return serviceInfo;
+    }
+
+    private static ServiceInfo addGameServiceMetaData(ServiceInfo serviceInfo, int resId) {
+        if (serviceInfo.metaData == null) {
+            serviceInfo.metaData = new Bundle();
+        }
+        serviceInfo.metaData.putInt(GameService.SERVICE_META_DATA, resId);
+
+        return serviceInfo;
+    }
+
+    private static SystemService.TargetUser managedTargetUser(UserHandle userHandle) {
+        return new SystemService.TargetUser(managedUserInfo(userHandle.getIdentifier()));
+    }
+
+    private static SystemService.TargetUser eligibleTargetUser(UserHandle userHandle) {
+        return new SystemService.TargetUser(eligibleUserInfo(userHandle.getIdentifier()));
+    }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/communal/CommunalManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/communal/CommunalManagerServiceTest.java
index d6db1b2..c46884f 100644
--- a/services/tests/mockingservicestests/src/com/android/server/communal/CommunalManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/communal/CommunalManagerServiceTest.java
@@ -16,57 +16,28 @@
 
 package com.android.server.communal;
 
-import static android.app.communal.CommunalManager.ALLOW_COMMUNAL_MODE_WITH_USER_CONSENT;
-import static android.content.Intent.ACTION_PACKAGE_REMOVED;
-import static android.content.pm.ActivityInfo.FLAG_SHOW_WHEN_LOCKED;
-
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
-import static com.android.server.wm.ActivityInterceptorCallback.COMMUNAL_MODE_ORDERED_ID;
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.spy;
 
 import android.Manifest;
-import android.annotation.Nullable;
-import android.app.KeyguardManager;
 import android.app.communal.ICommunalManager;
-import android.app.compat.CompatChanges;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
 import android.content.ContextWrapper;
-import android.content.Intent;
-import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
-import android.net.Uri;
 import android.os.RemoteException;
-import android.os.UserHandle;
 import android.platform.test.annotations.Presubmit;
-import android.provider.Settings;
-import android.service.dreams.DreamManagerInternal;
-import android.test.mock.MockContentResolver;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
 
-import com.android.internal.util.test.FakeSettingsProvider;
-import com.android.server.LocalServices;
-import com.android.server.SystemService;
-import com.android.server.wm.ActivityInterceptorCallback;
-import com.android.server.wm.ActivityTaskManagerInternal;
-
 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.MockitoSession;
 import org.mockito.junit.MockitoJUnitRunner;
 import org.mockito.quality.Strictness;
@@ -81,25 +52,9 @@
 @SmallTest
 @Presubmit
 public class CommunalManagerServiceTest {
-    private static final int TEST_USER_ID = 1;
-    private static final int TEST_REAL_CALLING_UID = 2;
-    private static final int TEST_REAL_CALLING_PID = 3;
-    private static final String TEST_CALLING_PACKAGE = "com.test.caller";
-    private static final String TEST_PACKAGE_NAME = "com.test.package";
-
     private MockitoSession mMockingSession;
     private CommunalManagerService mService;
 
-    @Mock
-    private ActivityTaskManagerInternal mAtmInternal;
-    @Mock
-    private KeyguardManager mKeyguardManager;
-    @Mock
-    private DreamManagerInternal mDreamManagerInternal;
-
-    private ActivityInterceptorCallback mActivityInterceptorCallback;
-    private BroadcastReceiver mPackageReceiver;
-    private ActivityInfo mAInfo;
     private ICommunalManager mBinder;
     private ContextWrapper mContextSpy;
 
@@ -107,19 +62,10 @@
     public final void setUp() {
         mMockingSession = mockitoSession()
                 .initMocks(this)
-                .spyStatic(CommunalManagerService.class)
-                .mockStatic(CompatChanges.class)
                 .strictness(Strictness.WARN)
                 .startMocking();
 
         mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getContext()));
-        MockContentResolver cr = new MockContentResolver(mContextSpy);
-        cr.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
-        when(mContextSpy.getContentResolver()).thenReturn(cr);
-
-        when(mContextSpy.getSystemService(KeyguardManager.class)).thenReturn(mKeyguardManager);
-        addLocalServiceMock(ActivityTaskManagerInternal.class, mAtmInternal);
-        addLocalServiceMock(DreamManagerInternal.class, mDreamManagerInternal);
 
         doNothing().when(mContextSpy).enforceCallingPermission(
                 eq(Manifest.permission.WRITE_COMMUNAL_STATE), anyString());
@@ -127,83 +73,16 @@
                 eq(Manifest.permission.READ_COMMUNAL_STATE), anyString());
 
         mService = new CommunalManagerService(mContextSpy);
-        mService.onBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START);
-
-        ArgumentCaptor<ActivityInterceptorCallback> activityInterceptorCaptor =
-                ArgumentCaptor.forClass(ActivityInterceptorCallback.class);
-        verify(mAtmInternal).registerActivityStartInterceptor(eq(COMMUNAL_MODE_ORDERED_ID),
-                activityInterceptorCaptor.capture());
-        mActivityInterceptorCallback = activityInterceptorCaptor.getValue();
-
-        ArgumentCaptor<BroadcastReceiver> packageReceiverCaptor =
-                ArgumentCaptor.forClass(BroadcastReceiver.class);
-        verify(mContextSpy).registerReceiverAsUser(packageReceiverCaptor.capture(),
-                eq(UserHandle.SYSTEM), any(), any(), any());
-        mPackageReceiver = packageReceiverCaptor.getValue();
-
         mBinder = mService.getBinderServiceInstance();
-
-        mAInfo = new ActivityInfo();
-        mAInfo.applicationInfo = new ApplicationInfo();
-        mAInfo.packageName = mAInfo.applicationInfo.packageName = TEST_PACKAGE_NAME;
     }
 
     @After
     public void tearDown() {
-        FakeSettingsProvider.clearSettingsProvider();
         if (mMockingSession != null) {
             mMockingSession.finishMocking();
         }
     }
 
-    /**
-     * Creates a mock and registers it to {@link LocalServices}.
-     */
-    private static <T> void addLocalServiceMock(Class<T> clazz, T mock) {
-        LocalServices.removeServiceForTest(clazz);
-        LocalServices.addService(clazz, mock);
-    }
-
-    private ActivityInterceptorCallback.ActivityInterceptorInfo buildActivityInfo(Intent intent) {
-        return new ActivityInterceptorCallback.ActivityInterceptorInfo(
-                TEST_REAL_CALLING_UID,
-                TEST_REAL_CALLING_PID,
-                TEST_USER_ID,
-                TEST_CALLING_PACKAGE,
-                "featureId",
-                intent,
-                null,
-                mAInfo,
-                "resolvedType",
-                TEST_REAL_CALLING_PID,
-                TEST_REAL_CALLING_UID,
-                null);
-    }
-
-    private void allowPackages(String packages) {
-        Settings.Secure.putStringForUser(mContextSpy.getContentResolver(),
-                Settings.Secure.COMMUNAL_MODE_PACKAGES, packages, UserHandle.USER_SYSTEM);
-    }
-
-    private String getAllowedPackages() {
-        return Settings.Secure.getStringForUser(mContextSpy.getContentResolver(),
-                Settings.Secure.COMMUNAL_MODE_PACKAGES, UserHandle.USER_SYSTEM);
-    }
-
-    private void assertDoesIntercept() {
-        final Intent intent = new Intent(Intent.ACTION_MAIN);
-        assertThat(mActivityInterceptorCallback.intercept(buildActivityInfo(intent))).isNotNull();
-    }
-
-    private void assertDoesNotIntercept() {
-        final Intent intent = new Intent(Intent.ACTION_MAIN);
-        assertThat(mActivityInterceptorCallback.intercept(buildActivityInfo(intent))).isNull();
-    }
-
-    private Intent createPackageIntent(String packageName, @Nullable String action) {
-        return new Intent(action, Uri.parse("package:" + packageName));
-    }
-
     @Test
     public void testIsCommunalMode_isTrue() throws RemoteException {
         mBinder.setCommunalViewShowing(true);
@@ -215,149 +94,4 @@
         mBinder.setCommunalViewShowing(false);
         assertThat(mBinder.isCommunalMode()).isFalse();
     }
-
-    @Test
-    public void testIntercept_unlocked_communalOff_appNotEnabled_showWhenLockedOff() {
-        when(mKeyguardManager.isKeyguardLocked()).thenReturn(false);
-        mAInfo.flags = 0;
-        assertDoesNotIntercept();
-    }
-
-    @Test
-    public void testIntercept_unlocked_communalOn_appNotEnabled_showWhenLockedOff()
-            throws RemoteException {
-        mBinder.setCommunalViewShowing(true);
-        when(mKeyguardManager.isKeyguardLocked()).thenReturn(false);
-        mAInfo.flags = 0;
-        assertDoesNotIntercept();
-    }
-
-    @Test
-    public void testIntercept_locked_communalOff_appNotEnabled_showWhenLockedOff() {
-        when(mKeyguardManager.isKeyguardLocked()).thenReturn(true);
-        mAInfo.flags = 0;
-        assertDoesNotIntercept();
-    }
-
-    @Test
-    public void testIntercept_locked_communalOn_appNotEnabled_showWhenLockedOff_allowlistEnabled()
-            throws RemoteException {
-        mBinder.setCommunalViewShowing(true);
-        when(mKeyguardManager.isKeyguardLocked()).thenReturn(true);
-        when(CompatChanges.isChangeEnabled(ALLOW_COMMUNAL_MODE_WITH_USER_CONSENT, TEST_PACKAGE_NAME,
-                UserHandle.SYSTEM)).thenReturn(true);
-        mAInfo.flags = 0;
-        assertDoesIntercept();
-    }
-
-    @Test
-    public void testIntercept_locked_communalOn_appNotEnabled_showWhenLockedOn_allowlistEnabled()
-            throws RemoteException {
-        mBinder.setCommunalViewShowing(true);
-        when(mKeyguardManager.isKeyguardLocked()).thenReturn(true);
-        when(CompatChanges.isChangeEnabled(ALLOW_COMMUNAL_MODE_WITH_USER_CONSENT, TEST_PACKAGE_NAME,
-                UserHandle.SYSTEM)).thenReturn(true);
-        mAInfo.flags = FLAG_SHOW_WHEN_LOCKED;
-
-        allowPackages("package1,package2");
-        assertDoesIntercept();
-    }
-
-    @Test
-    public void testIntercept_locked_communalOn_appEnabled_showWhenLockedOff_allowlistEnabled()
-            throws RemoteException {
-        mBinder.setCommunalViewShowing(true);
-        when(mKeyguardManager.isKeyguardLocked()).thenReturn(true);
-        when(CompatChanges.isChangeEnabled(ALLOW_COMMUNAL_MODE_WITH_USER_CONSENT, TEST_PACKAGE_NAME,
-                UserHandle.SYSTEM)).thenReturn(true);
-        mAInfo.flags = 0;
-
-        allowPackages(TEST_PACKAGE_NAME);
-        assertDoesIntercept();
-    }
-
-    @Test
-    public void testIntercept_locked_communalOn_appEnabled_showWhenLockedOn_allowlistEnabled()
-            throws RemoteException {
-        mBinder.setCommunalViewShowing(true);
-        when(mKeyguardManager.isKeyguardLocked()).thenReturn(true);
-        when(CompatChanges.isChangeEnabled(ALLOW_COMMUNAL_MODE_WITH_USER_CONSENT, TEST_PACKAGE_NAME,
-                UserHandle.SYSTEM)).thenReturn(true);
-
-        mAInfo.flags = FLAG_SHOW_WHEN_LOCKED;
-
-        allowPackages(TEST_PACKAGE_NAME);
-        assertDoesNotIntercept();
-    }
-
-    @Test
-    public void testIntercept_locked_communalOn_appEnabled_showWhenLockedOn_allowlistDisabled()
-            throws RemoteException {
-        mBinder.setCommunalViewShowing(true);
-        when(mKeyguardManager.isKeyguardLocked()).thenReturn(true);
-        when(CompatChanges.isChangeEnabled(ALLOW_COMMUNAL_MODE_WITH_USER_CONSENT, TEST_PACKAGE_NAME,
-                UserHandle.SYSTEM)).thenReturn(false);
-
-        mAInfo.flags = FLAG_SHOW_WHEN_LOCKED;
-
-        allowPackages(TEST_PACKAGE_NAME);
-        assertDoesIntercept();
-    }
-
-    @Test
-    public void testIntercept_locked_communalOn_dream() throws RemoteException {
-        mBinder.setCommunalViewShowing(true);
-        when(mKeyguardManager.isKeyguardLocked()).thenReturn(true);
-        when(mDreamManagerInternal.getActiveDreamComponent(false)).thenReturn(
-                new ComponentName(TEST_PACKAGE_NAME, "SomeClass"));
-
-        allowPackages(TEST_PACKAGE_NAME);
-        assertDoesNotIntercept();
-    }
-
-    @Test
-    public void testUpdateSettings_packageUninstalled() {
-        allowPackages("package1,package2");
-        assertThat(getAllowedPackages()).isEqualTo("package1,package2");
-
-        mPackageReceiver.onReceive(mContextSpy,
-                createPackageIntent("package1", ACTION_PACKAGE_REMOVED));
-
-        assertThat(getAllowedPackages()).isEqualTo("package2");
-    }
-
-    @Test
-    public void testUpdateSettings_nullAction_doesNothing() {
-        allowPackages("package1,package2");
-        assertThat(getAllowedPackages()).isEqualTo("package1,package2");
-
-        mPackageReceiver.onReceive(mContextSpy,
-                createPackageIntent("package1", null));
-
-        assertThat(getAllowedPackages()).isEqualTo("package1,package2");
-    }
-
-    @Test
-    public void testUpdateSettings_invalidPackage_doesNothing() {
-        allowPackages("package1,package2");
-        assertThat(getAllowedPackages()).isEqualTo("package1,package2");
-
-        mPackageReceiver.onReceive(mContextSpy,
-                createPackageIntent("package3", ACTION_PACKAGE_REMOVED));
-
-        assertThat(getAllowedPackages()).isEqualTo("package1,package2");
-    }
-
-    @Test
-    public void testUpdateSettings_onBoot() {
-        allowPackages("package1,package2");
-        assertThat(getAllowedPackages()).isEqualTo("package1,package2");
-
-        when(CommunalManagerService.isPackageInstalled(eq("package1"), any())).thenReturn(true);
-        when(CommunalManagerService.isPackageInstalled(eq("package2"), any())).thenReturn(false);
-
-        mService.onBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START);
-
-        assertThat(getAllowedPackages()).isEqualTo("package1");
-    }
 }
diff --git a/services/tests/mockingservicestests/src/com/android/server/compat/overrides/AppCompatOverridesServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/compat/overrides/AppCompatOverridesServiceTest.java
index 349da03..edf6816 100644
--- a/services/tests/mockingservicestests/src/com/android/server/compat/overrides/AppCompatOverridesServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/compat/overrides/AppCompatOverridesServiceTest.java
@@ -57,6 +57,8 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.compat.CompatibilityOverrideConfig;
+import com.android.internal.compat.CompatibilityOverridesByPackageConfig;
+import com.android.internal.compat.CompatibilityOverridesToRemoveByPackageConfig;
 import com.android.internal.compat.CompatibilityOverridesToRemoveConfig;
 import com.android.internal.compat.IPlatformCompat;
 import com.android.modules.utils.testing.TestableDeviceConfig.TestableDeviceConfigRule;
@@ -108,7 +110,13 @@
     @Captor
     private ArgumentCaptor<CompatibilityOverrideConfig> mOverridesToAddConfigCaptor;
     @Captor
+    private ArgumentCaptor<CompatibilityOverridesByPackageConfig>
+            mOverridesToAddByPackageConfigCaptor;
+    @Captor
     private ArgumentCaptor<CompatibilityOverridesToRemoveConfig> mOverridesToRemoveConfigCaptor;
+    @Captor
+    private ArgumentCaptor<CompatibilityOverridesToRemoveByPackageConfig>
+            mOverridesToRemoveByPackageConfigCaptor;
 
     @Rule
     public TestableDeviceConfigRule mDeviceConfigRule = new TestableDeviceConfigRule();
@@ -165,13 +173,19 @@
                 .setString(PACKAGE_3, "123:1:9:true,123:10:11:false,123:11::true")
                 .setString(PACKAGE_4, "").build());
 
+        verify(mPlatformCompat).putAllOverridesOnReleaseBuilds(
+                mOverridesToAddByPackageConfigCaptor.capture());
+        verify(mPlatformCompat).removeAllOverridesOnReleaseBuilds(
+                mOverridesToRemoveByPackageConfigCaptor.capture());
+        Map<String, CompatibilityOverrideConfig> packageNameToAddedOverrides =
+                mOverridesToAddByPackageConfigCaptor.getValue().packageNameToOverrides;
+        Map<String, CompatibilityOverridesToRemoveConfig> packageNameToRemovedOverrides =
+                mOverridesToRemoveByPackageConfigCaptor.getValue().packageNameToOverridesToRemove;
         Map<Long, PackageOverride> addedOverrides;
+        assertThat(packageNameToAddedOverrides.keySet()).containsExactly(PACKAGE_1, PACKAGE_3);
+        assertThat(packageNameToRemovedOverrides.keySet()).containsExactly(PACKAGE_3, PACKAGE_4);
         // Package 1
-        verify(mPlatformCompat).putOverridesOnReleaseBuilds(mOverridesToAddConfigCaptor.capture(),
-                eq(PACKAGE_1));
-        verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds(
-                any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_1));
-        addedOverrides = mOverridesToAddConfigCaptor.getValue().overrides;
+        addedOverrides = packageNameToAddedOverrides.get(PACKAGE_1).overrides;
         assertThat(addedOverrides).hasSize(3);
         assertThat(addedOverrides.get(123L)).isEqualTo(
                 new PackageOverride.Builder().setEnabled(true).build());
@@ -179,29 +193,17 @@
                 new PackageOverride.Builder().setMinVersionCode(2).setEnabled(true).build());
         assertThat(addedOverrides.get(789L)).isEqualTo(
                 new PackageOverride.Builder().setEnabled(false).build());
-        // Package 2
-        verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
-                any(CompatibilityOverrideConfig.class), eq(PACKAGE_2));
-        verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds(
-                any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_2));
         // Package 3
-        verify(mPlatformCompat).putOverridesOnReleaseBuilds(mOverridesToAddConfigCaptor.capture(),
-                eq(PACKAGE_3));
-        verify(mPlatformCompat).removeOverridesOnReleaseBuilds(
-                mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_3));
-        addedOverrides = mOverridesToAddConfigCaptor.getValue().overrides;
+        addedOverrides = packageNameToAddedOverrides.get(PACKAGE_3).overrides;
         assertThat(addedOverrides).hasSize(1);
         assertThat(addedOverrides.get(123L)).isEqualTo(
                 new PackageOverride.Builder().setMinVersionCode(10).setMaxVersionCode(
                         11).setEnabled(false).build());
-        assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(456L, 789L);
-        // Package 4
-        verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
-                any(CompatibilityOverrideConfig.class), eq(PACKAGE_4));
-        verify(mPlatformCompat).removeOverridesOnReleaseBuilds(
-                mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_4));
-        assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(123L, 456L,
+        assertThat(packageNameToRemovedOverrides.get(PACKAGE_3).changeIds).containsExactly(456L,
                 789L);
+        // Package 4
+        assertThat(packageNameToRemovedOverrides.get(PACKAGE_4).changeIds).containsExactly(123L,
+                456L, 789L);
     }
 
     @Test
@@ -213,11 +215,15 @@
         DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
                 .setString(PACKAGE_1, "123:::true").build());
 
-        verify(mPlatformCompat).putOverridesOnReleaseBuilds(mOverridesToAddConfigCaptor.capture(),
-                eq(PACKAGE_1));
-        verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds(
-                any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_1));
-        assertThat(mOverridesToAddConfigCaptor.getValue().overrides.keySet()).containsExactly(123L);
+        verify(mPlatformCompat).putAllOverridesOnReleaseBuilds(
+                mOverridesToAddByPackageConfigCaptor.capture());
+        verify(mPlatformCompat, never()).removeAllOverridesOnReleaseBuilds(
+                any(CompatibilityOverridesToRemoveByPackageConfig.class));
+        Map<String, CompatibilityOverrideConfig> packageNameToAddedOverrides =
+                mOverridesToAddByPackageConfigCaptor.getValue().packageNameToOverrides;
+        assertThat(packageNameToAddedOverrides.keySet()).containsExactly(PACKAGE_1);
+        assertThat(packageNameToAddedOverrides.get(PACKAGE_1).overrides.keySet()).containsExactly(
+                123L);
     }
 
     @Test
@@ -238,30 +244,28 @@
                 .setString(PACKAGE_2, "123:::true")
                 .setString(PACKAGE_3, "456:::true").build());
 
+        verify(mPlatformCompat).putAllOverridesOnReleaseBuilds(
+                mOverridesToAddByPackageConfigCaptor.capture());
+        verify(mPlatformCompat).removeAllOverridesOnReleaseBuilds(
+                mOverridesToRemoveByPackageConfigCaptor.capture());
+        Map<String, CompatibilityOverrideConfig> packageNameToAddedOverrides =
+                mOverridesToAddByPackageConfigCaptor.getValue().packageNameToOverrides;
+        Map<String, CompatibilityOverridesToRemoveConfig> packageNameToRemovedOverrides =
+                mOverridesToRemoveByPackageConfigCaptor.getValue().packageNameToOverridesToRemove;
+        assertThat(packageNameToAddedOverrides.keySet()).containsExactly(PACKAGE_1, PACKAGE_3);
+        assertThat(packageNameToRemovedOverrides.keySet()).containsExactly(PACKAGE_2, PACKAGE_3);
         // Package 1
-        verify(mPlatformCompat).putOverridesOnReleaseBuilds(mOverridesToAddConfigCaptor.capture(),
-                eq(PACKAGE_1));
-        verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds(
-                any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_1));
-        assertThat(mOverridesToAddConfigCaptor.getValue().overrides.keySet()).containsExactly(789L);
+        assertThat(packageNameToAddedOverrides.get(PACKAGE_1).overrides.keySet()).containsExactly(
+                789L);
         // Package 2
-        verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
-                any(CompatibilityOverrideConfig.class), eq(PACKAGE_2));
-        verify(mPlatformCompat).removeOverridesOnReleaseBuilds(
-                mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_2));
-        assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(456L, 789L);
+        assertThat(packageNameToRemovedOverrides.get(PACKAGE_2).changeIds).containsExactly(456L,
+                789L);
         // Package 3
-        verify(mPlatformCompat).putOverridesOnReleaseBuilds(mOverridesToAddConfigCaptor.capture(),
-                eq(PACKAGE_3));
-        verify(mPlatformCompat).removeOverridesOnReleaseBuilds(
-                mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_3));
-        assertThat(mOverridesToAddConfigCaptor.getValue().overrides.keySet()).containsExactly(456L);
-        assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(123L, 789L);
+        assertThat(packageNameToAddedOverrides.get(PACKAGE_3).overrides.keySet()).containsExactly(
+                456L);
+        assertThat(packageNameToRemovedOverrides.get(PACKAGE_3).changeIds).containsExactly(123L,
+                789L);
         // Package 4 (not applied because it hasn't changed after the listener was added)
-        verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
-                any(CompatibilityOverrideConfig.class), eq(PACKAGE_4));
-        verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds(
-                any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_4));
     }
 
     @Test
@@ -279,23 +283,28 @@
                 .setString(FLAG_REMOVE_OVERRIDES,
                         PACKAGE_1 + "=123:456," + PACKAGE_2 + "=*").build());
 
-        // Package 1
-        verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
-                any(CompatibilityOverrideConfig.class), eq(PACKAGE_1));
-        verify(mPlatformCompat, times(2)).removeOverridesOnReleaseBuilds(
-                mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_1));
-        List<CompatibilityOverridesToRemoveConfig> configs =
-                mOverridesToRemoveConfigCaptor.getAllValues();
+        verify(mPlatformCompat, never()).putAllOverridesOnReleaseBuilds(
+                any(CompatibilityOverridesByPackageConfig.class));
+        verify(mPlatformCompat, times(2)).removeAllOverridesOnReleaseBuilds(
+                mOverridesToRemoveByPackageConfigCaptor.capture());
+        List<CompatibilityOverridesToRemoveByPackageConfig> configs =
+                mOverridesToRemoveByPackageConfigCaptor.getAllValues();
         assertThat(configs.size()).isAtLeast(2);
-        assertThat(configs.get(configs.size() - 2).changeIds).containsExactly(123L, 456L);
-        assertThat(configs.get(configs.size() - 1).changeIds).containsExactly(789L);
-        // Package 2
-        verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
-                any(CompatibilityOverrideConfig.class), eq(PACKAGE_2));
-        verify(mPlatformCompat).removeOverridesOnReleaseBuilds(
-                mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_2));
-        assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(123L, 456L,
+        Map<String, CompatibilityOverridesToRemoveConfig> firstPackageNameToRemovedOverrides =
+                configs.get(configs.size() - 2).packageNameToOverridesToRemove;
+        Map<String, CompatibilityOverridesToRemoveConfig> secondPackageNameToRemovedOverrides =
+                configs.get(configs.size() - 1).packageNameToOverridesToRemove;
+        assertThat(firstPackageNameToRemovedOverrides.keySet()).containsExactly(PACKAGE_1,
+                PACKAGE_2);
+        assertThat(secondPackageNameToRemovedOverrides.keySet()).containsExactly(PACKAGE_1);
+        // Package 1
+        assertThat(firstPackageNameToRemovedOverrides.get(PACKAGE_1).changeIds).containsExactly(
+                123L, 456L);
+        assertThat(secondPackageNameToRemovedOverrides.get(PACKAGE_1).changeIds).containsExactly(
                 789L);
+        // Package 2
+        assertThat(firstPackageNameToRemovedOverrides.get(PACKAGE_2).changeIds).containsExactly(
+                123L, 456L, 789L);
     }
 
     @Test
@@ -315,34 +324,42 @@
                 .setString(FLAG_REMOVE_OVERRIDES, PACKAGE_2 + "=123," + PACKAGE_3 + "=789")
                 .setString(PACKAGE_2, "123:::true").build());
 
+        verify(mPlatformCompat).putAllOverridesOnReleaseBuilds(
+                mOverridesToAddByPackageConfigCaptor.capture());
+        verify(mPlatformCompat, times(2)).removeAllOverridesOnReleaseBuilds(
+                mOverridesToRemoveByPackageConfigCaptor.capture());
+        Map<String, CompatibilityOverrideConfig> packageNameToAddedOverrides =
+                mOverridesToAddByPackageConfigCaptor.getValue().packageNameToOverrides;
+        List<CompatibilityOverridesToRemoveByPackageConfig> removeConfigs =
+                mOverridesToRemoveByPackageConfigCaptor.getAllValues();
+        assertThat(removeConfigs.size()).isAtLeast(2);
+        Map<String, CompatibilityOverridesToRemoveConfig> firstPackageNameToRemovedOverrides =
+                removeConfigs.get(removeConfigs.size() - 2).packageNameToOverridesToRemove;
+        Map<String, CompatibilityOverridesToRemoveConfig> secondPackageNameToRemovedOverrides =
+                removeConfigs.get(removeConfigs.size() - 1).packageNameToOverridesToRemove;
+        assertThat(packageNameToAddedOverrides.keySet()).containsExactly(PACKAGE_1, PACKAGE_3);
+        assertThat(firstPackageNameToRemovedOverrides.keySet()).containsExactly(PACKAGE_2,
+                PACKAGE_3);
+        assertThat(secondPackageNameToRemovedOverrides.keySet()).containsExactly(PACKAGE_1,
+                PACKAGE_2,
+                PACKAGE_3);
         // Package 1
-        verify(mPlatformCompat).putOverridesOnReleaseBuilds(mOverridesToAddConfigCaptor.capture(),
-                eq(PACKAGE_1));
-        verify(mPlatformCompat).removeOverridesOnReleaseBuilds(
-                mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_1));
-        assertThat(mOverridesToAddConfigCaptor.getValue().overrides.keySet()).containsExactly(123L,
-                789L);
-        assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(456L);
+        assertThat(packageNameToAddedOverrides.get(PACKAGE_1).overrides.keySet()).containsExactly(
+                123L, 789L);
+        assertThat(secondPackageNameToRemovedOverrides.get(PACKAGE_1).changeIds).containsExactly(
+                456L);
         // Package 2
-        verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
-                any(CompatibilityOverrideConfig.class), eq(PACKAGE_2));
-        verify(mPlatformCompat, times(2)).removeOverridesOnReleaseBuilds(
-                mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_2));
-        List<CompatibilityOverridesToRemoveConfig> configs =
-                mOverridesToRemoveConfigCaptor.getAllValues();
-        assertThat(configs.size()).isAtLeast(2);
-        assertThat(configs.get(configs.size() - 2).changeIds).containsExactly(123L);
-        assertThat(configs.get(configs.size() - 1).changeIds).containsExactly(456L, 789L);
+        assertThat(firstPackageNameToRemovedOverrides.get(PACKAGE_2).changeIds).containsExactly(
+                123L);
+        assertThat(secondPackageNameToRemovedOverrides.get(PACKAGE_2).changeIds).containsExactly(
+                456L, 789L);
         // Package 3
-        verify(mPlatformCompat).putOverridesOnReleaseBuilds(mOverridesToAddConfigCaptor.capture(),
-                eq(PACKAGE_3));
-        verify(mPlatformCompat, times(2)).removeOverridesOnReleaseBuilds(
-                mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_3));
-        assertThat(mOverridesToAddConfigCaptor.getValue().overrides.keySet()).containsExactly(456L);
-        configs = mOverridesToRemoveConfigCaptor.getAllValues();
-        assertThat(configs.size()).isAtLeast(2);
-        assertThat(configs.get(configs.size() - 2).changeIds).containsExactly(789L);
-        assertThat(configs.get(configs.size() - 1).changeIds).containsExactly(123L);
+        assertThat(packageNameToAddedOverrides.get(PACKAGE_3).overrides.keySet()).containsExactly(
+                456L);
+        assertThat(firstPackageNameToRemovedOverrides.get(PACKAGE_3).changeIds).containsExactly(
+                789L);
+        assertThat(secondPackageNameToRemovedOverrides.get(PACKAGE_3).changeIds).containsExactly(
+                123L);
     }
 
     @Test
@@ -362,38 +379,41 @@
                 .setString(FLAG_OWNED_CHANGE_IDS, "123,456,789")
                 .setString(PACKAGE_2, "123:::true").build());
 
+        verify(mPlatformCompat).putAllOverridesOnReleaseBuilds(
+                mOverridesToAddByPackageConfigCaptor.capture());
+        verify(mPlatformCompat, times(2)).removeAllOverridesOnReleaseBuilds(
+                mOverridesToRemoveByPackageConfigCaptor.capture());
+        Map<String, CompatibilityOverrideConfig> packageNameToAddedOverrides =
+                mOverridesToAddByPackageConfigCaptor.getValue().packageNameToOverrides;
+        List<CompatibilityOverridesToRemoveByPackageConfig> removeConfigs =
+                mOverridesToRemoveByPackageConfigCaptor.getAllValues();
+        assertThat(removeConfigs.size()).isAtLeast(2);
+        Map<String, CompatibilityOverridesToRemoveConfig> firstPackageNameToRemovedOverrides =
+                removeConfigs.get(removeConfigs.size() - 2).packageNameToOverridesToRemove;
+        Map<String, CompatibilityOverridesToRemoveConfig> secondPackageNameToRemovedOverrides =
+                removeConfigs.get(removeConfigs.size() - 1).packageNameToOverridesToRemove;
+        assertThat(packageNameToAddedOverrides.keySet()).containsExactly(PACKAGE_2);
+        assertThat(firstPackageNameToRemovedOverrides.keySet()).containsExactly(PACKAGE_1);
+        assertThat(secondPackageNameToRemovedOverrides.keySet()).containsExactly(PACKAGE_2);
         // Package 1
-        verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
-                any(CompatibilityOverrideConfig.class), eq(PACKAGE_1));
-        verify(mPlatformCompat).removeOverridesOnReleaseBuilds(
-                mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_1));
-        assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(123L, 456L,
-                789L);
+        assertThat(firstPackageNameToRemovedOverrides.get(PACKAGE_1).changeIds).containsExactly(
+                123L, 456L, 789L);
         // Package 2
-        verify(mPlatformCompat).putOverridesOnReleaseBuilds(mOverridesToAddConfigCaptor.capture(),
-                eq(PACKAGE_2));
-        verify(mPlatformCompat).removeOverridesOnReleaseBuilds(
-                mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_2));
-        assertThat(mOverridesToAddConfigCaptor.getValue().overrides.keySet()).containsExactly(123L);
-        assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(456L, 789L);
-        // Package 3
-        verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
-                any(CompatibilityOverrideConfig.class), eq(PACKAGE_3));
-        verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds(
-                any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_3));
+        assertThat(packageNameToAddedOverrides.get(PACKAGE_2).overrides.keySet()).containsExactly(
+                123L);
+        assertThat(secondPackageNameToRemovedOverrides.get(PACKAGE_2).changeIds).containsExactly(
+                456L, 789L);
     }
 
     @Test
-    public void onPropertiesChanged_platformCompatThrowsExceptionForSomeCalls_skipsFailedCalls()
+    public void onPropertiesChanged_platformCompatThrowsExceptionForPutCall_skipsFailedCall()
             throws Exception {
         mockGetApplicationInfo(PACKAGE_1, /* versionCode= */ 0);
         mockGetApplicationInfo(PACKAGE_2, /* versionCode= */ 0);
         mockGetApplicationInfo(PACKAGE_3, /* versionCode= */ 0);
         mockGetApplicationInfo(PACKAGE_4, /* versionCode= */ 0);
-        doThrow(new RemoteException()).when(mPlatformCompat).putOverridesOnReleaseBuilds(
-                any(CompatibilityOverrideConfig.class), eq(PACKAGE_2));
-        doThrow(new RemoteException()).when(mPlatformCompat).removeOverridesOnReleaseBuilds(
-                any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_3));
+        doThrow(new RemoteException()).when(mPlatformCompat).putAllOverridesOnReleaseBuilds(
+                any(CompatibilityOverridesByPackageConfig.class));
 
         mService.registerDeviceConfigListeners();
         DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
@@ -403,26 +423,34 @@
                 .setString(PACKAGE_3, "123:::true")
                 .setString(PACKAGE_4, "123:::true").build());
 
-        // Package 1
-        verify(mPlatformCompat).putOverridesOnReleaseBuilds(any(CompatibilityOverrideConfig.class),
-                eq(PACKAGE_1));
-        verify(mPlatformCompat).removeOverridesOnReleaseBuilds(
-                any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_1));
-        // Package 2
-        verify(mPlatformCompat).putOverridesOnReleaseBuilds(any(CompatibilityOverrideConfig.class),
-                eq(PACKAGE_2));
-        verify(mPlatformCompat).removeOverridesOnReleaseBuilds(
-                any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_2));
-        // Package 3
-        verify(mPlatformCompat).putOverridesOnReleaseBuilds(any(CompatibilityOverrideConfig.class),
-                eq(PACKAGE_3));
-        verify(mPlatformCompat).removeOverridesOnReleaseBuilds(
-                any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_3));
-        // Package 4
-        verify(mPlatformCompat).putOverridesOnReleaseBuilds(any(CompatibilityOverrideConfig.class),
-                eq(PACKAGE_1));
-        verify(mPlatformCompat).removeOverridesOnReleaseBuilds(
-                any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_4));
+        verify(mPlatformCompat).putAllOverridesOnReleaseBuilds(
+                any(CompatibilityOverridesByPackageConfig.class));
+        verify(mPlatformCompat).removeAllOverridesOnReleaseBuilds(
+                any(CompatibilityOverridesToRemoveByPackageConfig.class));
+    }
+
+    @Test
+    public void onPropertiesChanged_platformCompatThrowsExceptionForRemoveCall_skipsFailedCall()
+            throws Exception {
+        mockGetApplicationInfo(PACKAGE_1, /* versionCode= */ 0);
+        mockGetApplicationInfo(PACKAGE_2, /* versionCode= */ 0);
+        mockGetApplicationInfo(PACKAGE_3, /* versionCode= */ 0);
+        mockGetApplicationInfo(PACKAGE_4, /* versionCode= */ 0);
+        doThrow(new RemoteException()).when(mPlatformCompat).removeAllOverridesOnReleaseBuilds(
+                any(CompatibilityOverridesToRemoveByPackageConfig.class));
+
+        mService.registerDeviceConfigListeners();
+        DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
+                .setString(FLAG_OWNED_CHANGE_IDS, "123,456")
+                .setString(PACKAGE_1, "123:::true")
+                .setString(PACKAGE_2, "123:::true")
+                .setString(PACKAGE_3, "123:::true")
+                .setString(PACKAGE_4, "123:::true").build());
+
+        verify(mPlatformCompat).putAllOverridesOnReleaseBuilds(
+                any(CompatibilityOverridesByPackageConfig.class));
+        verify(mPlatformCompat).removeAllOverridesOnReleaseBuilds(
+                any(CompatibilityOverridesToRemoveByPackageConfig.class));
     }
 
     @Test
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/gnss/hal/FakeGnssHal.java b/services/tests/mockingservicestests/src/com/android/server/location/gnss/hal/FakeGnssHal.java
index e0c8b09..93a2d31 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/gnss/hal/FakeGnssHal.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/gnss/hal/FakeGnssHal.java
@@ -234,6 +234,7 @@
         private boolean mMeasurementCollectionStarted = false;
         private boolean mMeasurementCollectionFullTracking = false;
         private boolean mMeasurementCollectionCorrVecOutputsEnabled = false;
+        private int mMeasurementCollectionIntervalMillis = 0;
         private GnssHalPositionMode mPositionMode = new GnssHalPositionMode();
         private GnssHalBatchingMode mBatchingMode = new GnssHalBatchingMode();
         private final ArrayList<Location> mBatchedLocations = new ArrayList<>();
@@ -428,11 +429,15 @@
     }
 
     @Override
-    protected void injectLocation(double latitude, double longitude, float accuracy) {
+    protected void injectLocation(@GnssLocationFlags int gnssLocationFlags, double latitude,
+            double longitude, double altitude, float speed, float bearing, float horizontalAccuracy,
+            float verticalAccuracy, float speedAccuracy, float bearingAccuracy, long timestamp,
+            @GnssRealtimeFlags int elapsedRealtimeFlags, long elapsedRealtimeNanos,
+            double elapsedRealtimeUncertaintyNanos) {
         mState.mInjectedLocation = new Location("injected");
         mState.mInjectedLocation.setLatitude(latitude);
         mState.mInjectedLocation.setLongitude(longitude);
-        mState.mInjectedLocation.setAccuracy(accuracy);
+        mState.mInjectedLocation.setAccuracy(horizontalAccuracy);
     }
 
     @Override
@@ -523,10 +528,11 @@
 
     @Override
     protected boolean startMeasurementCollection(boolean enableFullTracking,
-            boolean enableCorrVecOutputs) {
+            boolean enableCorrVecOutputs, int intervalMillis) {
         mState.mMeasurementCollectionStarted = true;
         mState.mMeasurementCollectionFullTracking = enableFullTracking;
         mState.mMeasurementCollectionCorrVecOutputsEnabled = enableCorrVecOutputs;
+        mState.mMeasurementCollectionIntervalMillis = intervalMillis;
         return true;
     }
 
@@ -535,6 +541,7 @@
         mState.mMeasurementCollectionStarted = false;
         mState.mMeasurementCollectionFullTracking = false;
         mState.mMeasurementCollectionCorrVecOutputsEnabled = false;
+        mState.mMeasurementCollectionIntervalMillis = 0;
         return true;
     }
 
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 ae5984a41..44a8b30 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
@@ -121,6 +121,9 @@
     /** The active map simulating the in memory storage of Settings  */
     private val mSettingsMap = WatchedArrayMap<String, PackageSetting>()
 
+    /** The shared libraries on the device */
+    private lateinit var mSharedLibraries: SharedLibrariesImpl
+
     init {
         PropertyInvalidatedCache.disableForTestMode()
         val apply = ExtendedMockito.mockitoSession()
@@ -324,6 +327,11 @@
                 any(AndroidPackage::class.java), anyBoolean(), any(File::class.java))) {
             PackageAbiHelper.NativeLibraryPaths("", false, "", "")
         }
+        whenever(mocks.injector.bootstrap(any(PackageManagerService::class.java))) {
+            mSharedLibraries = SharedLibrariesImpl(
+                getArgument<Any>(0) as PackageManagerService, mocks.injector)
+        }
+        whenever(mocks.injector.sharedLibrariesImpl) { mSharedLibraries }
         // everything visible by default
         whenever(mocks.appsFilter.shouldFilterApplication(
                 anyInt(), nullable(), nullable(), anyInt())) { false }
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/PackageFreezerTest.kt b/services/tests/mockingservicestests/src/com/android/server/pm/PackageFreezerTest.kt
new file mode 100644
index 0000000..edbfecc
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/PackageFreezerTest.kt
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm
+
+import android.os.Build
+import com.android.server.testutils.any
+import com.android.server.testutils.spy
+import com.android.server.testutils.whenever
+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.junit.runners.JUnit4
+import org.mockito.Mockito.eq
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
+import kotlin.test.assertFailsWith
+
+@RunWith(JUnit4::class)
+class PackageFreezerTest {
+
+    companion object {
+        const val TEST_PACKAGE = "com.android.test.package"
+        const val TEST_REASON = "test reason"
+        const val TEST_USER_ID = 0
+    }
+
+    @Rule
+    @JvmField
+    val rule = MockSystemRule()
+
+    lateinit var pms: PackageManagerService
+
+    private fun createPackageManagerService(vararg stageExistingPackages: String):
+            PackageManagerService {
+        stageExistingPackages.forEach {
+            rule.system().stageScanExistingPackage(it, 1L,
+                rule.system().dataAppDirectory)
+        }
+        var pms = PackageManagerService(rule.mocks().injector,
+            false /*coreOnly*/,
+            false /*factoryTest*/,
+            MockSystem.DEFAULT_VERSION_INFO.fingerprint,
+            false /*isEngBuild*/,
+            false /*isUserDebugBuild*/,
+            Build.VERSION_CODES.CUR_DEVELOPMENT,
+            Build.VERSION.INCREMENTAL,
+            false /*snapshotEnabled*/)
+        rule.system().validateFinalState()
+        return pms
+    }
+
+    private fun frozenMessage(packageName: String) = "Package $packageName is currently frozen!"
+
+    private fun <T : Throwable> assertThrowContainsMessage(
+        exceptionClass: kotlin.reflect.KClass<T>,
+        message: String,
+        block: () -> Unit
+    ) {
+        assertThat(assertFailsWith(exceptionClass, block).message).contains(message)
+    }
+
+    @Before
+    @Throws(Exception::class)
+    fun setup() {
+        rule.system().stageNominalSystemState()
+        pms = spy(createPackageManagerService(TEST_PACKAGE))
+        whenever(pms.killApplication(any(), any(), any(), any()))
+    }
+
+    @Test
+    fun freezePackage() {
+        val freezer = PackageFreezer(TEST_PACKAGE, TEST_USER_ID, TEST_REASON, pms)
+        verify(pms, times(1))
+            .killApplication(eq(TEST_PACKAGE), any(), eq(TEST_USER_ID), eq(TEST_REASON))
+
+        assertThrowContainsMessage(SecurityException::class, frozenMessage(TEST_PACKAGE)) {
+            pms.checkPackageStartable(TEST_PACKAGE, TEST_USER_ID)
+        }
+
+        freezer.close()
+        pms.checkPackageStartable(TEST_PACKAGE, TEST_USER_ID)
+    }
+
+    @Test
+    fun freezePackage_twice() {
+        val freezer1 = PackageFreezer(TEST_PACKAGE, TEST_USER_ID, TEST_REASON, pms)
+        val freezer2 = PackageFreezer(TEST_PACKAGE, TEST_USER_ID, TEST_REASON, pms)
+        verify(pms, times(2))
+            .killApplication(eq(TEST_PACKAGE), any(), eq(TEST_USER_ID), eq(TEST_REASON))
+
+        assertThrowContainsMessage(SecurityException::class, frozenMessage(TEST_PACKAGE)) {
+            pms.checkPackageStartable(TEST_PACKAGE, TEST_USER_ID)
+        }
+
+        freezer1.close()
+        assertThrowContainsMessage(SecurityException::class, frozenMessage(TEST_PACKAGE)) {
+            pms.checkPackageStartable(TEST_PACKAGE, TEST_USER_ID)
+        }
+
+        freezer2.close()
+        pms.checkPackageStartable(TEST_PACKAGE, TEST_USER_ID)
+    }
+
+    @Test
+    fun freezePackage_withoutClosing() {
+        var freezer: PackageFreezer? = PackageFreezer(TEST_PACKAGE, TEST_USER_ID, TEST_REASON, pms)
+        verify(pms, times(1))
+            .killApplication(eq(TEST_PACKAGE), any(), eq(TEST_USER_ID), eq(TEST_REASON))
+
+        assertThrowContainsMessage(SecurityException::class, frozenMessage(TEST_PACKAGE)) {
+            pms.checkPackageStartable(TEST_PACKAGE, TEST_USER_ID)
+        }
+
+        freezer = null
+        System.gc()
+        System.runFinalization()
+
+        pms.checkPackageStartable(TEST_PACKAGE, TEST_USER_ID)
+    }
+}
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 663bb2b..f2415b4 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java
@@ -41,7 +41,7 @@
 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.PackageInstaller.SessionInfo.SessionErrorCode;
 import android.content.pm.StagedApexInfo;
 import android.os.SystemProperties;
 import android.os.storage.IStorageManager;
@@ -774,7 +774,7 @@
         private boolean mIsReady = false;
         private boolean mIsApplied = false;
         private boolean mIsFailed = false;
-        private @StagedSessionErrorCode int mErrorCode = -1;
+        private @SessionErrorCode int mErrorCode = -1;
         private String mErrorMessage;
         private boolean mIsDestroyed = false;
         private int mParentSessionId = -1;
@@ -827,7 +827,7 @@
             return this;
         }
 
-        private @StagedSessionErrorCode int getErrorCode() {
+        private @SessionErrorCode int getErrorCode() {
             return mErrorCode;
         }
 
@@ -939,7 +939,7 @@
         }
 
         @Override
-        public void setSessionFailed(@StagedSessionErrorCode int errorCode, String errorMessage) {
+        public void setSessionFailed(@SessionErrorCode int errorCode, String errorMessage) {
             Preconditions.checkState(!mIsApplied, "Already marked as applied");
             mIsFailed = true;
             mErrorCode = errorCode;
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/TEST_MAPPING b/services/tests/mockingservicestests/src/com/android/server/pm/TEST_MAPPING
new file mode 100644
index 0000000..13e255fe4
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/TEST_MAPPING
@@ -0,0 +1,18 @@
+{
+  "presubmit": [
+    {
+      "name": "FrameworksMockingServicesTests",
+      "options": [
+        {
+            "include-filter": "com.android.server.pm"
+        },
+        {
+            "exclude-annotation": "androidx.test.filters.FlakyTest"
+        },
+        {
+            "exclude-annotation": "org.junit.Ignore"
+        }
+      ]
+    }
+  ]
+}
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 80f2729..202a54d 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -57,6 +57,7 @@
     <uses-permission android:name="android.permission.FORCE_STOP_PACKAGES"/>
     <uses-permission android:name="android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST"/>
     <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
+    <uses-permission android:name="android.permission.STATUS_BAR"/>
     <uses-permission android:name="android.permission.STATUS_BAR_SERVICE"/>
     <uses-permission android:name="android.permission.ACCESS_SURFACE_FLINGER"/>
     <uses-permission android:name="android.permission.READ_FRAME_BUFFER"/>
@@ -97,6 +98,10 @@
     <uses-permission
         android:name="android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD"/>
 
+    <queries>
+        <package android:name="com.android.servicestests.apps.suspendtestapp" />
+    </queries>
+
     <!-- Uses API introduced in O (26) -->
     <uses-sdk android:minSdkVersion="1"
          android:targetSdkVersion="26"/>
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java
index e93e544..82b7540 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java
@@ -247,4 +247,21 @@
         verify(mMockServiceClient).onPerformGestureResult(0, false);
     }
 
+    @Test
+    public void unbind_resetAllMagnification() {
+        mConnection.unbindLocked();
+        verify(mMockMagnificationProcessor).resetAllIfNeeded(anyInt());
+    }
+
+    @Test
+    public void binderDied_resetAllMagnification() {
+        setServiceBinding(COMPONENT_NAME);
+        mConnection.bindLocked();
+        mConnection.onServiceConnected(COMPONENT_NAME, mMockIBinder);
+
+        mConnection.binderDied();
+
+        verify(mMockMagnificationProcessor).resetAllIfNeeded(anyInt());
+    }
+
 }
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/MagnificationProcessorTest.java b/services/tests/servicestests/src/com/android/server/accessibility/MagnificationProcessorTest.java
index 621507e..99d6c2a 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/MagnificationProcessorTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/MagnificationProcessorTest.java
@@ -24,6 +24,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.doAnswer;
 import static org.mockito.Mockito.verify;
@@ -235,7 +236,17 @@
 
         mMagnificationProcessor.resetCurrentMagnification(TEST_DISPLAY, /* animate= */false);
 
-        verify(mMockWindowMagnificationManager).reset(TEST_DISPLAY);
+        verify(mMockWindowMagnificationManager).disableWindowMagnification(TEST_DISPLAY, false,
+                null);
+    }
+
+    @Test
+    public void resetAllIfNeeded_resetFullscreenAndWindowMagnificationByConnectionId() {
+        final int connectionId = 1;
+        mMagnificationProcessor.resetAllIfNeeded(connectionId);
+
+        verify(mMockFullScreenMagnificationController).resetAllIfNeeded(eq(connectionId));
+        verify(mMockWindowMagnificationManager).resetAllIfNeeded(eq(connectionId));
     }
 
     @Test
@@ -322,7 +333,7 @@
         final MagnificationConfig result = mMagnificationProcessor.getMagnificationConfig(
                 TEST_DISPLAY);
         verify(mMockMagnificationController).transitionMagnificationConfigMode(eq(TEST_DISPLAY),
-                eq(newConfig), anyBoolean());
+                eq(newConfig), anyBoolean(), anyInt());
         assertConfigEquals(newConfig, result);
     }
 
@@ -438,7 +449,7 @@
                     anyFloat(), anyFloat(), anyFloat());
             doAnswer(enableWindowMagnificationStubAnswer).when(
                     mWindowMagnificationManager).enableWindowMagnification(eq(TEST_DISPLAY),
-                    anyFloat(), anyFloat(), anyFloat(), any());
+                    anyFloat(), anyFloat(), anyFloat(), any(), anyInt());
         }
 
         public void resetAndStubMethods() {
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
index 08421de..0054fc3 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
@@ -125,6 +125,7 @@
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
         FakeSettingsProvider.clearSettingsProvider();
+        final Object globalLock = new Object();
 
         LocalServices.removeServiceForTest(WindowManagerInternal.class);
         LocalServices.addService(WindowManagerInternal.class, mMockWindowManagerInternal);
@@ -139,14 +140,14 @@
                 CURRENT_USER_ID);
         mScaleProvider = spy(new MagnificationScaleProvider(mContext));
         mWindowMagnificationManager = Mockito.spy(
-                new WindowMagnificationManager(mContext, CURRENT_USER_ID,
+                new WindowMagnificationManager(mContext, globalLock,
                         mock(WindowMagnificationManager.Callback.class), mTraceManager,
                         mScaleProvider));
         mMockConnection = new MockWindowMagnificationConnection(true);
         mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
         mScreenMagnificationControllerStubber = new FullScreenMagnificationControllerStubber(
                 mScreenMagnificationController);
-        mMagnificationController = new MagnificationController(mService, new Object(), mContext,
+        mMagnificationController = new MagnificationController(mService, globalLock, mContext,
                 mScreenMagnificationController, mWindowMagnificationManager, mScaleProvider);
 
         mMagnificationController.setMagnificationCapabilities(
@@ -293,7 +294,7 @@
 
         // Enable window magnification while animating.
         mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, DEFAULT_SCALE,
-                Float.NaN, Float.NaN, null);
+                Float.NaN, Float.NaN, null, TEST_SERVICE_ID);
         mMockConnection.invokeCallbacks();
 
         assertTrue(mWindowMagnificationManager.isWindowMagnifierEnabled(TEST_DISPLAY));
@@ -310,7 +311,7 @@
 
         mMagnificationController.transitionMagnificationConfigMode(TEST_DISPLAY,
                 obtainMagnificationConfig(MODE_WINDOW),
-                false);
+                false, TEST_SERVICE_ID);
 
         verify(mScreenMagnificationController).reset(eq(TEST_DISPLAY), eq(false));
         mMockConnection.invokeCallbacks();
@@ -325,13 +326,13 @@
         activateMagnifier(MODE_WINDOW, MAGNIFIED_CENTER_X, MAGNIFIED_CENTER_Y);
         mMagnificationController.transitionMagnificationConfigMode(TEST_DISPLAY,
                 obtainMagnificationConfig(MODE_FULLSCREEN),
-                animate);
+                animate, TEST_SERVICE_ID);
         mMockConnection.invokeCallbacks();
 
         assertFalse(mWindowMagnificationManager.isWindowMagnifierEnabled(TEST_DISPLAY));
         verify(mScreenMagnificationController).setScaleAndCenter(TEST_DISPLAY,
                 DEFAULT_SCALE, MAGNIFIED_CENTER_X, MAGNIFIED_CENTER_Y,
-                animate, MAGNIFICATION_GESTURE_HANDLER_ID);
+                animate, TEST_SERVICE_ID);
     }
 
     @Test
@@ -345,7 +346,7 @@
         // Config-setting mode
         mMagnificationController.transitionMagnificationConfigMode(TEST_DISPLAY,
                 obtainMagnificationConfig(MODE_FULLSCREEN),
-                true);
+                true, TEST_SERVICE_ID);
 
         assertEquals(DEFAULT_SCALE, mScreenMagnificationController.getScale(TEST_DISPLAY), 0);
         assertEquals(MAGNIFIED_CENTER_X, mScreenMagnificationController.getCenterX(TEST_DISPLAY),
@@ -365,7 +366,7 @@
         // Config-setting mode
         mMagnificationController.transitionMagnificationConfigMode(TEST_DISPLAY,
                 obtainMagnificationConfig(MODE_FULLSCREEN),
-                true);
+                true, TEST_SERVICE_ID);
 
         verify(mTransitionCallBack, never()).onResult(TEST_DISPLAY, true);
     }
@@ -772,7 +773,7 @@
                     centerY, true, AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
         } else {
             mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, DEFAULT_SCALE,
-                    centerX, centerY, null);
+                    centerX, centerY, null, TEST_SERVICE_ID);
             mMockConnection.invokeCallbacks();
         }
     }
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MockWindowMagnificationConnection.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MockWindowMagnificationConnection.java
index 0659a60..4c03ec3 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MockWindowMagnificationConnection.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MockWindowMagnificationConnection.java
@@ -35,6 +35,9 @@
 import android.view.accessibility.IWindowMagnificationConnection;
 import android.view.accessibility.IWindowMagnificationConnectionCallback;
 
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * Mocks the basic logic of window magnification in System UI. We assume the screen size is
  * unlimited, so source bounds is always on the center of the mirror window bounds.
@@ -42,6 +45,8 @@
 class MockWindowMagnificationConnection {
 
     public static final int TEST_DISPLAY = Display.DEFAULT_DISPLAY;
+    public static final int TEST_DISPLAY_2 = Display.DEFAULT_DISPLAY + 1;
+    private final List mValidDisplayIds;
     private final IWindowMagnificationConnection mConnection;
     private final Binder mBinder;
     private final boolean mSuspendCallback;
@@ -60,6 +65,10 @@
     }
 
     MockWindowMagnificationConnection(boolean suspendCallback) throws RemoteException {
+        mValidDisplayIds = new ArrayList();
+        mValidDisplayIds.add(TEST_DISPLAY);
+        mValidDisplayIds.add(TEST_DISPLAY_2);
+
         mSuspendCallback = suspendCallback;
         mConnection = mock(IWindowMagnificationConnection.class);
         mBinder = mock(Binder.class);
@@ -86,8 +95,8 @@
     private void stubEnableWindowMagnification() throws RemoteException {
         doAnswer((invocation) -> {
             final int displayId = invocation.getArgument(0);
-            if (displayId != TEST_DISPLAY) {
-                throw new IllegalArgumentException("only support default display :" + displayId);
+            if (!mValidDisplayIds.contains(displayId)) {
+                throw new IllegalArgumentException("Not support display :" + displayId);
             }
             mWindowMagnificationEnabled = true;
             final float scale = invocation.getArgument(1);
@@ -107,8 +116,8 @@
     private void stubDisableWindowMagnification() throws RemoteException {
         doAnswer((invocation) -> {
             final int displayId = invocation.getArgument(0);
-            if (displayId != TEST_DISPLAY) {
-                throw new IllegalArgumentException("only support default display :" + displayId);
+            if (!mValidDisplayIds.contains(displayId)) {
+                throw new IllegalArgumentException("Not support display :" + displayId);
             }
             setAnimationCallback(invocation.getArgument(1));
             mHasPendingCallback = true;
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java
index b807c11..e9f0bd9 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java
@@ -85,7 +85,7 @@
     @Before
     public void setUp() throws RemoteException {
         MockitoAnnotations.initMocks(this);
-        mWindowMagnificationManager = new WindowMagnificationManager(mContext, 0,
+        mWindowMagnificationManager = new WindowMagnificationManager(mContext, new Object(),
                 mock(WindowMagnificationManager.Callback.class), mMockTrace,
                 new MagnificationScaleProvider(mContext));
         mMockConnection = new MockWindowMagnificationConnection();
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java
index 85512f3..a62c0d5 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java
@@ -16,6 +16,9 @@
 
 package com.android.server.accessibility.magnification;
 
+import static com.android.server.accessibility.magnification.MockWindowMagnificationConnection.TEST_DISPLAY;
+import static com.android.server.accessibility.magnification.MockWindowMagnificationConnection.TEST_DISPLAY_2;
+
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.eq;
@@ -38,13 +41,13 @@
 import android.content.IntentFilter;
 import android.graphics.PointF;
 import android.graphics.Rect;
+import android.graphics.Region;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.test.mock.MockContentResolver;
-import android.view.Display;
 import android.view.InputDevice;
 import android.view.MotionEvent;
 import android.view.accessibility.IRemoteMagnificationAnimationCallback;
@@ -67,8 +70,8 @@
  */
 public class WindowMagnificationManagerTest {
 
-    private static final int TEST_DISPLAY = Display.DEFAULT_DISPLAY;
     private static final int CURRENT_USER_ID = UserHandle.USER_SYSTEM;
+    private static final int SERVICE_ID = 1;
 
     private MockWindowMagnificationConnection mMockConnection;
     @Mock
@@ -91,7 +94,7 @@
         LocalServices.addService(StatusBarManagerInternal.class, mMockStatusBarManagerInternal);
         mResolver = new MockContentResolver();
         mMockConnection = new MockWindowMagnificationConnection();
-        mWindowMagnificationManager = new WindowMagnificationManager(mContext, CURRENT_USER_ID,
+        mWindowMagnificationManager = new WindowMagnificationManager(mContext, new Object(),
                 mMockCallback, mMockTrace, new MagnificationScaleProvider(mContext));
 
         when(mContext.getContentResolver()).thenReturn(mResolver);
@@ -185,7 +188,7 @@
         mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
 
         mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 2f, 200f, 300f,
-                mAnimationCallback);
+                mAnimationCallback, SERVICE_ID);
 
         verify(mMockConnection.getConnection()).enableWindowMagnification(eq(TEST_DISPLAY), eq(2f),
                 eq(200f), eq(300f), eq(0f), eq(0f),
@@ -377,14 +380,51 @@
     }
 
     @Test
-    public void resetMagnification_enabled_windowMagnifierDisabled() {
+    public void requestConnectionToNull_expectedGetterResults() {
         mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
-        mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 3f, NaN, NaN);
-        assertTrue(mWindowMagnificationManager.isWindowMagnifierEnabled(TEST_DISPLAY));
+        mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 3f, 1, 1);
 
-        mWindowMagnificationManager.reset(TEST_DISPLAY);
+        mWindowMagnificationManager.requestConnection(false);
+
+        assertEquals(1f, mWindowMagnificationManager.getScale(TEST_DISPLAY), 0);
+        assertTrue(Float.isNaN(mWindowMagnificationManager.getCenterX(TEST_DISPLAY)));
+        assertTrue(Float.isNaN(mWindowMagnificationManager.getCenterY(TEST_DISPLAY)));
+        final Region bounds = new Region();
+        mWindowMagnificationManager.getMagnificationSourceBounds(TEST_DISPLAY, bounds);
+        assertTrue(bounds.isEmpty());
+    }
+
+    @Test
+    public void resetAllMagnification_enabledBySameId_windowMagnifiersDisabled() {
+        mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
+        mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 3f,
+                100f, 200f, null, WindowMagnificationManager.WINDOW_POSITION_AT_CENTER, SERVICE_ID);
+        mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY_2, 3f,
+                100f, 200f, null, WindowMagnificationManager.WINDOW_POSITION_AT_CENTER, SERVICE_ID);
+        assertTrue(mWindowMagnificationManager.isWindowMagnifierEnabled(TEST_DISPLAY));
+        assertTrue(mWindowMagnificationManager.isWindowMagnifierEnabled(TEST_DISPLAY_2));
+
+        mWindowMagnificationManager.resetAllIfNeeded(SERVICE_ID);
 
         assertFalse(mWindowMagnificationManager.isWindowMagnifierEnabled(TEST_DISPLAY));
+        assertFalse(mWindowMagnificationManager.isWindowMagnifierEnabled(TEST_DISPLAY_2));
+    }
+
+    @Test
+    public void resetAllMagnification_enabledByDifferentId_windowMagnifierDisabled() {
+        final int serviceId2 = SERVICE_ID + 1;
+        mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
+        mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 3f,
+                100f, 200f, null, WindowMagnificationManager.WINDOW_POSITION_AT_CENTER, SERVICE_ID);
+        mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY_2, 3f,
+                100f, 200f, null, WindowMagnificationManager.WINDOW_POSITION_AT_CENTER, serviceId2);
+        assertTrue(mWindowMagnificationManager.isWindowMagnifierEnabled(TEST_DISPLAY));
+        assertTrue(mWindowMagnificationManager.isWindowMagnifierEnabled(TEST_DISPLAY_2));
+
+        mWindowMagnificationManager.resetAllIfNeeded(SERVICE_ID);
+
+        assertFalse(mWindowMagnificationManager.isWindowMagnifierEnabled(TEST_DISPLAY));
+        assertTrue(mWindowMagnificationManager.isWindowMagnifierEnabled(TEST_DISPLAY_2));
     }
 
     @Test
@@ -439,6 +479,22 @@
     }
 
     @Test
+    public void magnifierGetters_disabled_expectedValues() {
+        mWindowMagnificationManager.requestConnection(true);
+        mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 3f,
+                100f, 200f, WindowMagnificationManager.WINDOW_POSITION_AT_CENTER);
+
+        mWindowMagnificationManager.disableWindowMagnification(TEST_DISPLAY, false);
+
+        assertEquals(1f, mWindowMagnificationManager.getScale(TEST_DISPLAY), 0);
+        assertTrue(Float.isNaN(mWindowMagnificationManager.getCenterX(TEST_DISPLAY)));
+        assertTrue(Float.isNaN(mWindowMagnificationManager.getCenterY(TEST_DISPLAY)));
+        final Region bounds = new Region();
+        mWindowMagnificationManager.getMagnificationSourceBounds(TEST_DISPLAY, bounds);
+        assertTrue(bounds.isEmpty());
+    }
+
+    @Test
     public void onDisplayRemoved_enabledOnTestDisplay_disabled() {
         mWindowMagnificationManager.requestConnection(true);
         mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 3f, 100f, 200f);
diff --git a/services/tests/servicestests/src/com/android/server/autofill/AutofillManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/autofill/AutofillManagerServiceTest.java
index d5a28f6..d2ea9c4 100644
--- a/services/tests/servicestests/src/com/android/server/autofill/AutofillManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/autofill/AutofillManagerServiceTest.java
@@ -15,7 +15,7 @@
  */
 package com.android.server.autofill;
 
-import static com.android.server.autofill.AutofillManagerService.getWhitelistedCompatModePackages;
+import static com.android.server.autofill.AutofillManagerService.getAllowedCompatModePackages;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -29,54 +29,54 @@
 public class AutofillManagerServiceTest {
 
     @Test
-    public void testGetWhitelistedCompatModePackages_null() {
-        assertThat(getWhitelistedCompatModePackages(null)).isNull();
+    public void testGetAllowedCompatModePackages_null() {
+        assertThat(getAllowedCompatModePackages(null)).isNull();
     }
 
     @Test
-    public void testGetWhitelistedCompatModePackages_empty() {
-        assertThat(getWhitelistedCompatModePackages("")).isNull();
+    public void testGetAllowedCompatModePackages_empty() {
+        assertThat(getAllowedCompatModePackages("")).isNull();
     }
 
     @Test
-    public void testGetWhitelistedCompatModePackages_onePackageNoUrls() {
-        assertThat(getWhitelistedCompatModePackages("one_is_the_loniest_package"))
+    public void testGetAllowedCompatModePackages_onePackageNoUrls() {
+        assertThat(getAllowedCompatModePackages("one_is_the_loniest_package"))
                 .containsExactly("one_is_the_loniest_package", null);
     }
 
     @Test
-    public void testGetWhitelistedCompatModePackages_onePackageMissingEndDelimiter() {
-        assertThat(getWhitelistedCompatModePackages("one_is_the_loniest_package[")).isEmpty();
+    public void testGetAllowedCompatModePackages_onePackageMissingEndDelimiter() {
+        assertThat(getAllowedCompatModePackages("one_is_the_loniest_package[")).isEmpty();
     }
 
     @Test
-    public void testGetWhitelistedCompatModePackages_onePackageOneUrl() {
+    public void testGetAllowedCompatModePackages_onePackageOneUrl() {
         final Map<String, String[]> result =
-                getWhitelistedCompatModePackages("one_is_the_loniest_package[url]");
+                getAllowedCompatModePackages("one_is_the_loniest_package[url]");
         assertThat(result).hasSize(1);
         assertThat(result.get("one_is_the_loniest_package")).asList().containsExactly("url");
     }
 
     @Test
-    public void testGetWhitelistedCompatModePackages_onePackageMultipleUrls() {
+    public void testGetAllowedCompatModePackages_onePackageMultipleUrls() {
         final Map<String, String[]> result =
-                getWhitelistedCompatModePackages("one_is_the_loniest_package[4,5,8,15,16,23,42]");
+                getAllowedCompatModePackages("one_is_the_loniest_package[4,5,8,15,16,23,42]");
         assertThat(result).hasSize(1);
         assertThat(result.get("one_is_the_loniest_package")).asList()
             .containsExactly("4", "5", "8", "15", "16", "23", "42");
     }
 
     @Test
-    public void testGetWhitelistedCompatModePackages_multiplePackagesOneInvalid() {
-        final Map<String, String[]> result = getWhitelistedCompatModePackages("one:two[");
+    public void testGetAllowedCompatModePackages_multiplePackagesOneInvalid() {
+        final Map<String, String[]> result = getAllowedCompatModePackages("one:two[");
         assertThat(result).hasSize(1);
         assertThat(result.get("one")).isNull();
     }
 
     @Test
-    public void testGetWhitelistedCompatModePackages_multiplePackagesMultipleUrls() {
+    public void testGetAllowedCompatModePackages_multiplePackagesMultipleUrls() {
         final Map<String, String[]> result =
-                getWhitelistedCompatModePackages("p1[p1u1]:p2:p3[p3u1,p3u2]");
+                getAllowedCompatModePackages("p1[p1u1]:p2:p3[p3u1,p3u2]");
         assertThat(result).hasSize(3);
         assertThat(result.get("p1")).asList().containsExactly("p1u1");
         assertThat(result.get("p2")).isNull();
@@ -84,9 +84,9 @@
     }
 
     @Test
-    public void testGetWhitelistedCompatModePackages_threePackagesOneInvalid() {
+    public void testGetAllowedCompatModePackages_threePackagesOneInvalid() {
         final Map<String, String[]> result =
-                getWhitelistedCompatModePackages("p1[p1u1]:p2[:p3[p3u1,p3u2]");
+                getAllowedCompatModePackages("p1[p1u1]:p2[:p3[p3u1,p3u2]");
         assertThat(result).hasSize(2);
         assertThat(result.get("p1")).asList().containsExactly("p1u1");
         assertThat(result.get("p3")).asList().containsExactly("p3u1", "p3u2");
diff --git a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
index d926dcb..b2854ce 100644
--- a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
@@ -36,6 +36,8 @@
 
 import com.android.internal.compat.AndroidBuildClassifier;
 import com.android.internal.compat.CompatibilityOverrideConfig;
+import com.android.internal.compat.CompatibilityOverridesByPackageConfig;
+import com.android.internal.compat.CompatibilityOverridesToRemoveByPackageConfig;
 import com.android.internal.compat.CompatibilityOverridesToRemoveConfig;
 
 import org.junit.Before;
@@ -303,6 +305,51 @@
         assertThat(compatConfig.isChangeEnabled(unknownChangeId, applicationInfo)).isTrue();
     }
 
+    @Test
+    public void testInstallerCanAddOverridesForMultiplePackages() throws Exception {
+        final String packageName1 = "com.some.package1";
+        final String packageName2 = "com.some.package2";
+        final long disabledChangeId1 = 1234L;
+        final long disabledChangeId2 = 1235L;
+        CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+                .addDisabledOverridableChangeWithId(disabledChangeId1)
+                .addDisabledOverridableChangeWithId(disabledChangeId2)
+                .build();
+        ApplicationInfo applicationInfo1 = ApplicationInfoBuilder.create()
+                .withPackageName(packageName1)
+                .build();
+        ApplicationInfo applicationInfo2 = ApplicationInfoBuilder.create()
+                .withPackageName(packageName2)
+                .build();
+        PackageManager packageManager = mock(PackageManager.class);
+        when(mContext.getPackageManager()).thenReturn(packageManager);
+        when(packageManager.getApplicationInfo(eq(packageName1), anyInt()))
+                .thenReturn(applicationInfo1);
+        when(packageManager.getApplicationInfo(eq(packageName2), anyInt()))
+                .thenReturn(applicationInfo2);
+
+        // Force the validator to prevent overriding non-overridable changes by using a user build.
+        when(mBuildClassifier.isDebuggableBuild()).thenReturn(false);
+        when(mBuildClassifier.isFinalBuild()).thenReturn(true);
+        Map<Long, PackageOverride> overrides1 = new HashMap<>();
+        overrides1.put(disabledChangeId1, new PackageOverride.Builder().setEnabled(true).build());
+        Map<Long, PackageOverride> overrides2 = new HashMap<>();
+        overrides2.put(disabledChangeId1, new PackageOverride.Builder().setEnabled(true).build());
+        overrides2.put(disabledChangeId2, new PackageOverride.Builder().setEnabled(true).build());
+        Map<String, CompatibilityOverrideConfig> packageNameToOverrides = new HashMap<>();
+        packageNameToOverrides.put(packageName1, new CompatibilityOverrideConfig(overrides1));
+        packageNameToOverrides.put(packageName2, new CompatibilityOverrideConfig(overrides2));
+        CompatibilityOverridesByPackageConfig config = new CompatibilityOverridesByPackageConfig(
+                packageNameToOverrides);
+
+        compatConfig.addAllPackageOverrides(config, /* skipUnknownChangeIds */ true);
+
+        assertThat(compatConfig.isChangeEnabled(disabledChangeId1, applicationInfo1)).isTrue();
+        assertThat(compatConfig.isChangeEnabled(disabledChangeId2, applicationInfo1)).isFalse();
+        assertThat(compatConfig.isChangeEnabled(disabledChangeId1, applicationInfo2)).isTrue();
+        assertThat(compatConfig.isChangeEnabled(disabledChangeId2, applicationInfo2)).isTrue();
+    }
+
 
     @Test
     public void testPreventInstallerSetNonOverridable() throws Exception {
@@ -641,6 +688,73 @@
     }
 
     @Test
+    public void testInstallerCanRemoveOverridesForMultiplePackages() throws Exception {
+        final String packageName1 = "com.some.package1";
+        final String packageName2 = "com.some.package2";
+        final long disabledChangeId1 = 1234L;
+        final long disabledChangeId2 = 1235L;
+        final long enabledChangeId = 1236L;
+        CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+                .addDisabledOverridableChangeWithId(disabledChangeId1)
+                .addDisabledOverridableChangeWithId(disabledChangeId2)
+                .addEnabledOverridableChangeWithId(enabledChangeId)
+                .build();
+        ApplicationInfo applicationInfo1 = ApplicationInfoBuilder.create()
+                .withPackageName(packageName1)
+                .build();
+        ApplicationInfo applicationInfo2 = ApplicationInfoBuilder.create()
+                .withPackageName(packageName2)
+                .build();
+        PackageManager packageManager = mock(PackageManager.class);
+        when(mContext.getPackageManager()).thenReturn(packageManager);
+        when(packageManager.getApplicationInfo(eq(packageName1), anyInt()))
+                .thenReturn(applicationInfo1);
+        when(packageManager.getApplicationInfo(eq(packageName2), anyInt()))
+                .thenReturn(applicationInfo2);
+
+        assertThat(compatConfig.addOverride(disabledChangeId1, packageName1, true)).isTrue();
+        assertThat(compatConfig.addOverride(disabledChangeId2, packageName1, true)).isTrue();
+        assertThat(compatConfig.addOverride(enabledChangeId, packageName1, false)).isTrue();
+        assertThat(compatConfig.addOverride(disabledChangeId1, packageName2, true)).isTrue();
+        assertThat(compatConfig.addOverride(disabledChangeId2, packageName2, true)).isTrue();
+        assertThat(compatConfig.addOverride(enabledChangeId, packageName2, false)).isTrue();
+        assertThat(compatConfig.isChangeEnabled(disabledChangeId1, applicationInfo1)).isTrue();
+        assertThat(compatConfig.isChangeEnabled(disabledChangeId2, applicationInfo1)).isTrue();
+        assertThat(compatConfig.isChangeEnabled(enabledChangeId, applicationInfo1)).isFalse();
+        assertThat(compatConfig.isChangeEnabled(disabledChangeId1, applicationInfo1)).isTrue();
+        assertThat(compatConfig.isChangeEnabled(disabledChangeId2, applicationInfo1)).isTrue();
+        assertThat(compatConfig.isChangeEnabled(enabledChangeId, applicationInfo1)).isFalse();
+
+        // Force the validator to prevent overriding non-overridable changes by using a user build.
+        when(mBuildClassifier.isDebuggableBuild()).thenReturn(false);
+        when(mBuildClassifier.isFinalBuild()).thenReturn(true);
+
+        Set<Long> overridesToRemove1 = new HashSet<>();
+        overridesToRemove1.add(disabledChangeId1);
+        overridesToRemove1.add(enabledChangeId);
+        Set<Long> overridesToRemove2 = new HashSet<>();
+        overridesToRemove2.add(disabledChangeId1);
+        overridesToRemove2.add(disabledChangeId2);
+        Map<String, CompatibilityOverridesToRemoveConfig> packageNameToOverridesToRemove =
+                new HashMap<>();
+        packageNameToOverridesToRemove.put(packageName1,
+                new CompatibilityOverridesToRemoveConfig(overridesToRemove1));
+        packageNameToOverridesToRemove.put(packageName2,
+                new CompatibilityOverridesToRemoveConfig(overridesToRemove2));
+        CompatibilityOverridesToRemoveByPackageConfig config =
+                new CompatibilityOverridesToRemoveByPackageConfig(packageNameToOverridesToRemove);
+
+        compatConfig.removeAllPackageOverrides(config);
+
+        assertThat(compatConfig.isChangeEnabled(disabledChangeId1, applicationInfo1)).isFalse();
+        assertThat(compatConfig.isChangeEnabled(disabledChangeId2, applicationInfo1)).isTrue();
+        assertThat(compatConfig.isChangeEnabled(enabledChangeId, applicationInfo1)).isTrue();
+        assertThat(compatConfig.isChangeEnabled(disabledChangeId1, applicationInfo2)).isFalse();
+        assertThat(compatConfig.isChangeEnabled(disabledChangeId2, applicationInfo2)).isFalse();
+        assertThat(compatConfig.isChangeEnabled(enabledChangeId, applicationInfo2)).isFalse();
+    }
+
+    @Test
     public void testPreventInstallerRemoveNonOverridable() throws Exception {
         final long disabledChangeId1 = 1234L;
         final long disabledChangeId2 = 1235L;
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
index 70641c2..b811e28 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
@@ -129,6 +129,7 @@
 import android.net.NetworkStatsHistory;
 import android.net.NetworkTemplate;
 import android.net.TelephonyNetworkSpecifier;
+import android.net.wifi.WifiInfo;
 import android.os.Binder;
 import android.os.Handler;
 import android.os.INetworkManagementService;
@@ -226,13 +227,13 @@
 
     private static final long TEST_START = 1194220800000L;
     private static final String TEST_IFACE = "test0";
-    private static final String TEST_SSID = "AndroidAP";
+    private static final String TEST_WIFI_NETWORK_KEY = "TestWifiNetworkKey";
     private static final String TEST_IMSI = "310210";
     private static final int TEST_SUB_ID = 42;
     private static final Network TEST_NETWORK = mock(Network.class, CALLS_REAL_METHODS);
 
 
-    private static NetworkTemplate sTemplateWifi = buildTemplateWifi(TEST_SSID);
+    private static NetworkTemplate sTemplateWifi = buildTemplateWifi(TEST_WIFI_NETWORK_KEY);
     private static NetworkTemplate sTemplateCarrierMetered =
             buildTemplateCarrierMetered(TEST_IMSI);
 
@@ -1986,9 +1987,8 @@
         assertEquals("Unexpected template match rule in network policies",
                 NetworkTemplate.MATCH_CARRIER,
                 actualPolicy.template.getMatchRule());
-        assertEquals("Unexpected subscriberId match rule in network policies",
-                NetworkTemplate.SUBSCRIBER_ID_MATCH_RULE_EXACT,
-                actualPolicy.template.getSubscriberIdMatchRule());
+        assertTrue("Unexpected subscriberIds size in network policies",
+                actualPolicy.template.getSubscriberIds().size() > 0);
         assertEquals("Unexpected template meteredness in network policies",
                 METERED_YES, actualPolicy.template.getMeteredness());
     }
@@ -2003,9 +2003,8 @@
         assertEquals("Unexpected template match rule in network policies",
                 NetworkTemplate.MATCH_WIFI,
                 actualPolicy.template.getMatchRule());
-        assertEquals("Unexpected subscriberId match rule in network policies",
-                NetworkTemplate.SUBSCRIBER_ID_MATCH_RULE_ALL,
-                actualPolicy.template.getSubscriberIdMatchRule());
+        assertEquals("Unexpected subscriberIds size in network policies",
+                actualPolicy.template.getSubscriberIds().size(), 0);
         assertEquals("Unexpected template meteredness in network policies",
                 METERED_NO, actualPolicy.template.getMeteredness());
     }
@@ -2098,10 +2097,13 @@
     }
 
     private static NetworkStateSnapshot buildWifi() {
+        WifiInfo mockWifiInfo = mock(WifiInfo.class);
+        when(mockWifiInfo.makeCopy(anyLong())).thenReturn(mockWifiInfo);
+        when(mockWifiInfo.getCurrentNetworkKey()).thenReturn(TEST_WIFI_NETWORK_KEY);
         final LinkProperties prop = new LinkProperties();
         prop.setInterfaceName(TEST_IFACE);
         final NetworkCapabilities networkCapabilities = new NetworkCapabilities.Builder()
-                .addTransportType(TRANSPORT_WIFI).setSsid(TEST_SSID).build();
+                .addTransportType(TRANSPORT_WIFI).setTransportInfo(mockWifiInfo).build();
         return new NetworkStateSnapshot(TEST_NETWORK, networkCapabilities, prop,
                 null /*subscriberId*/, TYPE_WIFI);
     }
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java
index 6c4ae6f..62a2b1b 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java
@@ -306,12 +306,12 @@
         assertEquals(expected.stageCid, actual.stageCid);
         assertEquals(expected.isPrepared(), actual.isPrepared());
         assertEquals(expected.isStaged(), actual.isStaged());
-        assertEquals(expected.isStagedSessionApplied(), actual.isStagedSessionApplied());
-        assertEquals(expected.isStagedSessionFailed(), actual.isStagedSessionFailed());
-        assertEquals(expected.isStagedSessionReady(), actual.isStagedSessionReady());
-        assertEquals(expected.getStagedSessionErrorCode(), actual.getStagedSessionErrorCode());
-        assertEquals(expected.getStagedSessionErrorMessage(),
-                actual.getStagedSessionErrorMessage());
+        assertEquals(expected.isSessionApplied(), actual.isSessionApplied());
+        assertEquals(expected.isSessionFailed(), actual.isSessionFailed());
+        assertEquals(expected.isSessionReady(), actual.isSessionReady());
+        assertEquals(expected.getSessionErrorCode(), actual.getSessionErrorCode());
+        assertEquals(expected.getSessionErrorMessage(),
+                actual.getSessionErrorMessage());
         assertEquals(expected.isPrepared(), actual.isPrepared());
         assertEquals(expected.isCommitted(), actual.isCommitted());
         assertEquals(expected.createdMillis, actual.createdMillis);
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 6c9f8fe..9d67240 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -48,6 +48,7 @@
 import android.os.Process;
 import android.os.UserHandle;
 import android.platform.test.annotations.Presubmit;
+import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.AtomicFile;
 import android.util.Log;
@@ -109,6 +110,8 @@
     @Mock
     DomainVerificationManagerInternal mDomainVerificationManager;
 
+    final ArrayMap<String, Long> mOrigFirstInstallTimes = new ArrayMap<>();
+
     @Before
     public void initializeMocks() {
         MockitoAnnotations.initMocks(this);
@@ -208,14 +211,14 @@
                 new WatchableTester(settingsUnderTest, "noSuspendingPackage");
         watcher.register();
         settingsUnderTest.mPackages.put(PACKAGE_NAME_1, createPackageSetting(PACKAGE_NAME_1));
-        settingsUnderTest.readPackageRestrictionsLPr(0);
+        settingsUnderTest.readPackageRestrictionsLPr(0, mOrigFirstInstallTimes);
         watcher.verifyChangeReported("put package 1");
         // Collect a snapshot at the midway point (package 2 has not been added)
         final Settings snapshot = settingsUnderTest.snapshot();
         watcher.verifyNoChangeReported("snapshot");
         settingsUnderTest.mPackages.put(PACKAGE_NAME_2, createPackageSetting(PACKAGE_NAME_2));
         watcher.verifyChangeReported("put package 2");
-        settingsUnderTest.readPackageRestrictionsLPr(0);
+        settingsUnderTest.readPackageRestrictionsLPr(0, mOrigFirstInstallTimes);
 
         PackageSetting ps1 = settingsUnderTest.mPackages.get(PACKAGE_NAME_1);
         PackageUserStateInternal packageUserState1 = ps1.readUserState(0);
@@ -251,7 +254,7 @@
         watcher.register();
         settingsUnderTest.mPackages.put(PACKAGE_NAME_1, createPackageSetting(PACKAGE_NAME_1));
         watcher.verifyChangeReported("put package 1");
-        settingsUnderTest.readPackageRestrictionsLPr(0);
+        settingsUnderTest.readPackageRestrictionsLPr(0, mOrigFirstInstallTimes);
         watcher.verifyChangeReported("readPackageRestrictions");
 
         final PackageSetting ps1 = settingsUnderTest.mPackages.get(PACKAGE_NAME_1);
@@ -264,17 +267,17 @@
         final SuspendParams params = packageUserState1.getSuspendParams().valueAt(0);
         watcher.verifyNoChangeReported("fetch user state");
         assertThat(params, is(notNullValue()));
-        assertThat(params.appExtras.size(), is(1));
-        assertThat(params.appExtras.getString("app_extra_string"), is("value"));
-        assertThat(params.launcherExtras.size(), is(1));
-        assertThat(params.launcherExtras.getLong("launcher_extra_long"), is(4L));
-        assertThat(params.dialogInfo, is(notNullValue()));
-        assertThat(params.dialogInfo.getDialogMessage(), is("Dialog Message"));
-        assertThat(params.dialogInfo.getTitleResId(), is(ID_NULL));
-        assertThat(params.dialogInfo.getIconResId(), is(TEST_RESOURCE_ID));
-        assertThat(params.dialogInfo.getNeutralButtonTextResId(), is(ID_NULL));
-        assertThat(params.dialogInfo.getNeutralButtonAction(), is(BUTTON_ACTION_MORE_DETAILS));
-        assertThat(params.dialogInfo.getDialogMessageResId(), is(ID_NULL));
+        assertThat(params.getAppExtras().size(), is(1));
+        assertThat(params.getAppExtras().getString("app_extra_string"), is("value"));
+        assertThat(params.getLauncherExtras().size(), is(1));
+        assertThat(params.getLauncherExtras().getLong("launcher_extra_long"), is(4L));
+        assertThat(params.getDialogInfo(), is(notNullValue()));
+        assertThat(params.getDialogInfo().getDialogMessage(), is("Dialog Message"));
+        assertThat(params.getDialogInfo().getTitleResId(), is(ID_NULL));
+        assertThat(params.getDialogInfo().getIconResId(), is(TEST_RESOURCE_ID));
+        assertThat(params.getDialogInfo().getNeutralButtonTextResId(), is(ID_NULL));
+        assertThat(params.getDialogInfo().getNeutralButtonAction(), is(BUTTON_ACTION_MORE_DETAILS));
+        assertThat(params.getDialogInfo().getDialogMessageResId(), is(ID_NULL));
     }
 
     @Test
@@ -338,7 +341,7 @@
         settingsUnderTest.mPackages.put(PACKAGE_NAME_3, createPackageSetting(PACKAGE_NAME_3));
         watcher.verifyChangeReported("put package 3");
         // now read and verify
-        settingsUnderTest.readPackageRestrictionsLPr(0);
+        settingsUnderTest.readPackageRestrictionsLPr(0, mOrigFirstInstallTimes);
         watcher.verifyChangeReported("readPackageRestrictions");
         final PackageUserStateInternal readPus1 = settingsUnderTest.mPackages.get(PACKAGE_NAME_1)
                 .readUserState(0);
@@ -351,18 +354,18 @@
         final SuspendParams params11 = readPus1.getSuspendParams().valueAt(0);
         watcher.verifyNoChangeReported("read package param");
         assertThat(params11, is(notNullValue()));
-        assertThat(params11.dialogInfo, is(dialogInfo1));
-        assertThat(BaseBundle.kindofEquals(params11.appExtras, appExtras1), is(true));
-        assertThat(BaseBundle.kindofEquals(params11.launcherExtras, launcherExtras1),
+        assertThat(params11.getDialogInfo(), is(dialogInfo1));
+        assertThat(BaseBundle.kindofEquals(params11.getAppExtras(), appExtras1), is(true));
+        assertThat(BaseBundle.kindofEquals(params11.getLauncherExtras(), launcherExtras1),
                 is(true));
         watcher.verifyNoChangeReported("read package param");
 
         assertThat(readPus1.getSuspendParams().keyAt(1), is("suspendingPackage2"));
         final SuspendParams params12 = readPus1.getSuspendParams().valueAt(1);
         assertThat(params12, is(notNullValue()));
-        assertThat(params12.dialogInfo, is(dialogInfo2));
-        assertThat(BaseBundle.kindofEquals(params12.appExtras, appExtras2), is(true));
-        assertThat(BaseBundle.kindofEquals(params12.launcherExtras, launcherExtras2),
+        assertThat(params12.getDialogInfo(), is(dialogInfo2));
+        assertThat(BaseBundle.kindofEquals(params12.getAppExtras(), appExtras2), is(true));
+        assertThat(BaseBundle.kindofEquals(params12.getLauncherExtras(), launcherExtras2),
                 is(true));
         watcher.verifyNoChangeReported("read package param");
 
@@ -373,9 +376,9 @@
         assertThat(readPus2.getSuspendParams().keyAt(0), is("suspendingPackage3"));
         final SuspendParams params21 = readPus2.getSuspendParams().valueAt(0);
         assertThat(params21, is(notNullValue()));
-        assertThat(params21.dialogInfo, is(nullValue()));
-        assertThat(BaseBundle.kindofEquals(params21.appExtras, appExtras1), is(true));
-        assertThat(params21.launcherExtras, is(nullValue()));
+        assertThat(params21.getDialogInfo(), is(nullValue()));
+        assertThat(BaseBundle.kindofEquals(params21.getAppExtras(), appExtras1), is(true));
+        assertThat(params21.getLauncherExtras(), is(nullValue()));
         watcher.verifyNoChangeReported("read package param");
 
         final PackageUserStateInternal readPus3 = settingsUnderTest.mPackages.get(PACKAGE_NAME_3)
@@ -388,7 +391,7 @@
     @Test
     public void testPackageRestrictionsSuspendedDefault() {
         final PackageSetting defaultSetting = createPackageSetting(PACKAGE_NAME_1);
-        assertThat(defaultSetting.getSuspended(0), is(false));
+        assertThat(defaultSetting.getUserStateOrDefault(0).isSuspended(), is(false));
     }
 
     @Test
@@ -418,7 +421,7 @@
         settingsUnderTest.mPackages.put(PACKAGE_NAME_2, createPackageSetting(PACKAGE_NAME_2));
         settingsUnderTest.mPackages.put(PACKAGE_NAME_3, createPackageSetting(PACKAGE_NAME_3));
         // now read and verify
-        settingsUnderTest.readPackageRestrictionsLPr(0);
+        settingsUnderTest.readPackageRestrictionsLPr(0, mOrigFirstInstallTimes);
         final PackageUserState readPus1 = settingsUnderTest.mPackages.get(PACKAGE_NAME_1)
                 .readUserState(0);
         assertThat(readPus1.getDistractionFlags(), is(distractionFlags1));
@@ -1127,7 +1130,6 @@
         assertSame(origPkgSetting.getCpuAbiOverride(), testPkgSetting.getCpuAbiOverride());
         assertThat(origPkgSetting.getCpuAbiOverride(), is(testPkgSetting.getCpuAbiOverride()));
         assertThat(origPkgSetting.getDomainSetId(), is(testPkgSetting.getDomainSetId()));
-        assertThat(origPkgSetting.getFirstInstallTime(), is(testPkgSetting.getFirstInstallTime()));
         assertSame(origPkgSetting.getInstallSource(), testPkgSetting.getInstallSource());
         assertThat(origPkgSetting.isInstallPermissionsFixed(),
                 is(testPkgSetting.isInstallPermissionsFixed()));
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java
index 828d419c..1e4134e 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java
@@ -82,7 +82,8 @@
         assertThat(testUserState.equals(oldUserState), is(false));
 
         oldUserState = new PackageUserStateImpl();
-        oldUserState.setSuspended(true);
+        oldUserState.putSuspendParams("suspendingPackage",
+                SuspendParams.getInstanceOrNull(null, new PersistableBundle(), null));
         assertThat(testUserState.equals(oldUserState), is(false));
 
         oldUserState = new PackageUserStateImpl();
@@ -231,7 +232,6 @@
 
 
         final PackageUserStateImpl testUserState1 = new PackageUserStateImpl();
-        testUserState1.setSuspended(true);
         testUserState1.setSuspendParams(paramsMap1);
 
         PackageUserStateImpl testUserState2 =
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest12.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest12.java
index 0708be2..78bcf0c 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest12.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest12.java
@@ -147,6 +147,11 @@
         // Verifies pushDynamicShortcuts further persists shortcuts into AppSearch without
         // removing previous shortcuts when max number of shortcuts is reached.
         mManager.pushDynamicShortcut(makeShortcut("s6"));
+        // Increasing the max number of shortcuts since number of results per page in AppSearch
+        // is set to match the former.
+        mService.updateConfigurationLocked(
+                ShortcutService.ConfigConstants.KEY_MAX_SHORTCUTS + "=10,"
+                        + ShortcutService.ConfigConstants.KEY_SAVE_DELAY_MILLIS + "=1");
         shortcuts = getAllPersistedShortcuts();
         assertNotNull(shortcuts);
         assertEquals(6, shortcuts.size());
@@ -281,7 +286,7 @@
 
     private List<ShortcutInfo> getAllPersistedShortcuts() {
         try {
-            SystemClock.sleep(500);
+            SystemClock.sleep(5000);
             final AndroidFuture<List<ShortcutInfo>> future = new AndroidFuture<>();
             getPersistedShortcut(future);
             return future.get(10, TimeUnit.SECONDS);
diff --git a/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java b/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java
index 2290ef7..398148f 100644
--- a/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java
@@ -25,23 +25,16 @@
 
 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.junit.Assert.fail;
-import static org.junit.Assume.assumeTrue;
 
 import android.app.AppGlobals;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
 import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
 import android.content.pm.IPackageManager;
 import android.content.pm.LauncherApps;
 import android.content.pm.PackageManager;
 import android.content.pm.SuspendDialogInfo;
-import android.content.res.Resources;
 import android.os.BaseBundle;
 import android.os.Bundle;
 import android.os.Handler;
@@ -50,13 +43,6 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.UserHandle;
-import android.support.test.uiautomator.By;
-import android.support.test.uiautomator.UiDevice;
-import android.support.test.uiautomator.UiObject2;
-import android.support.test.uiautomator.Until;
-import android.util.Log;
-import android.view.IWindowManager;
-import android.view.WindowManagerGlobal;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.FlakyTest;
@@ -65,7 +51,6 @@
 
 import com.android.internal.app.IAppOpsCallback;
 import com.android.internal.app.IAppOpsService;
-import com.android.servicestests.apps.suspendtestapp.SuspendTestActivity;
 import com.android.servicestests.apps.suspendtestapp.SuspendTestReceiver;
 
 import org.junit.After;
@@ -76,7 +61,6 @@
 import java.io.IOException;
 import java.util.Arrays;
 import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.SynchronousQueue;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicReference;
 
@@ -84,8 +68,6 @@
 @LargeTest
 @FlakyTest
 public class SuspendPackagesTest {
-    private static final String TAG = SuspendPackagesTest.class.getSimpleName();
-    private static final String TEST_APP_LABEL = "Suspend Test App";
     private static final String TEST_APP_PACKAGE_NAME = SuspendTestReceiver.PACKAGE_NAME;
     private static final String[] PACKAGES_TO_SUSPEND = new String[]{TEST_APP_PACKAGE_NAME};
 
@@ -105,75 +87,11 @@
     public static final String EXTRA_RECEIVED_PACKAGE_NAME =
             SuspendPackagesTest.INSTRUMENTATION_PACKAGE + ".extra.RECEIVED_PACKAGE_NAME";
 
-
     private Context mContext;
     private PackageManager mPackageManager;
     private LauncherApps mLauncherApps;
     private Handler mReceiverHandler;
-    private AppCommunicationReceiver mAppCommsReceiver;
     private StubbedCallback mTestCallback;
-    private UiDevice mUiDevice;
-    private ComponentName mDeviceAdminComponent;
-    private boolean mPoSet;
-    private boolean mDoSet;
-
-    private static final class AppCommunicationReceiver extends BroadcastReceiver {
-        private Context context;
-        private boolean registered;
-        private SynchronousQueue<Intent> intentQueue = new SynchronousQueue<>();
-
-        AppCommunicationReceiver(Context context) {
-            this.context = context;
-        }
-
-        void register(Handler handler, String... actions) {
-            registered = true;
-            final IntentFilter intentFilter = new IntentFilter();
-            for (String action : actions) {
-                intentFilter.addAction(action);
-            }
-            context.registerReceiver(this, intentFilter, null, handler);
-        }
-
-        void unregister() {
-            if (registered) {
-                context.unregisterReceiver(this);
-            }
-        }
-
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            Log.d(TAG, "AppCommunicationReceiver#onReceive: " + intent.getAction());
-            try {
-                intentQueue.offer(intent, 5, TimeUnit.SECONDS);
-            } catch (InterruptedException ie) {
-                throw new RuntimeException("Receiver thread interrupted", ie);
-            }
-        }
-
-        Intent pollForIntent(long secondsToWait) {
-            if (!registered) {
-                throw new IllegalStateException("Receiver not registered");
-            }
-            final Intent intent;
-            try {
-                intent = intentQueue.poll(secondsToWait, TimeUnit.SECONDS);
-            } catch (InterruptedException ie) {
-                throw new RuntimeException("Interrupted while waiting for app broadcast", ie);
-            }
-            return intent;
-        }
-
-        void drainPendingBroadcasts() {
-            while (pollForIntent(5) != null) ;
-        }
-
-        Intent receiveIntentFromApp() {
-            final Intent intentReceived = pollForIntent(5);
-            assertNotNull("No intent received from app within 5 seconds", intentReceived);
-            return intentReceived;
-        }
-    }
 
     @Before
     public void setUp() {
@@ -181,9 +99,6 @@
         mPackageManager = mContext.getPackageManager();
         mLauncherApps = (LauncherApps) mContext.getSystemService(Context.LAUNCHER_APPS_SERVICE);
         mReceiverHandler = new Handler(Looper.getMainLooper());
-        mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
-        mDeviceAdminComponent = new ComponentName(mContext,
-                "com.android.server.devicepolicy.DummyDeviceAdmins$Admin1");
         IPackageManager ipm = AppGlobals.getPackageManager();
         try {
             // Otherwise implicit broadcasts will not be delivered.
@@ -192,31 +107,6 @@
             e.rethrowAsRuntimeException();
         }
         unsuspendTestPackage();
-        mAppCommsReceiver = new AppCommunicationReceiver(mContext);
-    }
-
-    /**
-     * Care should be taken when used with {@link #mAppCommsReceiver} in the same test as both use
-     * the same handler.
-     */
-    private Bundle requestAppAction(String action) throws InterruptedException {
-        final AtomicReference<Bundle> result = new AtomicReference<>();
-        final CountDownLatch receiverLatch = new CountDownLatch(1);
-        final ComponentName testReceiverComponent = new ComponentName(TEST_APP_PACKAGE_NAME,
-                SuspendTestReceiver.class.getCanonicalName());
-        final Intent broadcastIntent = new Intent(action)
-                .setComponent(testReceiverComponent)
-                .setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
-        mContext.sendOrderedBroadcast(broadcastIntent, null, new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                result.set(getResultExtras(true));
-                receiverLatch.countDown();
-            }
-        }, mReceiverHandler, 0, null, null);
-
-        assertTrue("Test receiver timed out ", receiverLatch.await(5, TimeUnit.SECONDS));
-        return result.get();
     }
 
     private PersistableBundle getExtras(String keyPrefix, long lval, String sval, double dval) {
@@ -240,14 +130,6 @@
         assertTrue("setPackagesSuspended returned non-empty list", unchangedPackages.length == 0);
     }
 
-    private void startTestAppActivity() {
-        final Intent testActivity = new Intent()
-                .setComponent(new ComponentName(TEST_APP_PACKAGE_NAME,
-                        SuspendTestActivity.class.getCanonicalName()))
-                .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        mContext.startActivity(testActivity);
-    }
-
     private static boolean areSameExtras(BaseBundle expected, BaseBundle received) {
         if (expected != null) {
             expected.get(""); // hack to unparcel the bundles.
@@ -265,93 +147,6 @@
     }
 
     @Test
-    public void testIsPackageSuspended() throws Exception {
-        suspendTestPackage(null, null, null);
-        assertTrue("isPackageSuspended is false",
-                mPackageManager.isPackageSuspended(TEST_APP_PACKAGE_NAME));
-    }
-
-    @Test
-    public void testSuspendedStateFromApp() throws Exception {
-        Bundle resultFromApp = requestAppAction(SuspendTestReceiver.ACTION_GET_SUSPENDED_STATE);
-        assertFalse(resultFromApp.getBoolean(SuspendTestReceiver.EXTRA_SUSPENDED, true));
-        assertNull(resultFromApp.getBundle(SuspendTestReceiver.EXTRA_SUSPENDED_APP_EXTRAS));
-
-        final PersistableBundle appExtras = getExtras("testSuspendedStateFromApp", 20, "20", 0.2);
-        suspendTestPackage(appExtras, null, null);
-
-        resultFromApp = requestAppAction(SuspendTestReceiver.ACTION_GET_SUSPENDED_STATE);
-        assertTrue("resultFromApp:suspended is false",
-                resultFromApp.getBoolean(SuspendTestReceiver.EXTRA_SUSPENDED));
-        final Bundle receivedAppExtras =
-                resultFromApp.getBundle(SuspendTestReceiver.EXTRA_SUSPENDED_APP_EXTRAS);
-        assertSameExtras("Received app extras different to the ones supplied",
-                appExtras, receivedAppExtras);
-    }
-
-    @Test
-    public void testMyPackageSuspendedUnsuspended() {
-        mAppCommsReceiver.register(mReceiverHandler, ACTION_REPORT_MY_PACKAGE_SUSPENDED,
-                ACTION_REPORT_MY_PACKAGE_UNSUSPENDED);
-        mAppCommsReceiver.drainPendingBroadcasts();
-        final PersistableBundle appExtras = getExtras("testMyPackageSuspendBroadcasts", 1, "1", .1);
-        suspendTestPackage(appExtras, null, null);
-        Intent intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
-        assertEquals("MY_PACKAGE_SUSPENDED delivery not reported",
-                ACTION_REPORT_MY_PACKAGE_SUSPENDED, intentFromApp.getAction());
-        assertSameExtras("Received app extras different to the ones supplied", appExtras,
-                intentFromApp.getBundleExtra(SuspendTestReceiver.EXTRA_SUSPENDED_APP_EXTRAS));
-        unsuspendTestPackage();
-        intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
-        assertEquals("MY_PACKAGE_UNSUSPENDED delivery not reported",
-                ACTION_REPORT_MY_PACKAGE_UNSUSPENDED, intentFromApp.getAction());
-    }
-
-    @Test
-    public void testUpdatingAppExtras() {
-        mAppCommsReceiver.register(mReceiverHandler, ACTION_REPORT_MY_PACKAGE_SUSPENDED);
-        final PersistableBundle extras1 = getExtras("testMyPackageSuspendedOnChangingExtras", 1,
-                "1", 0.1);
-        suspendTestPackage(extras1, null, null);
-        Intent intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
-        assertEquals("MY_PACKAGE_SUSPENDED delivery not reported",
-                ACTION_REPORT_MY_PACKAGE_SUSPENDED, intentFromApp.getAction());
-        assertSameExtras("Received app extras different to the ones supplied", extras1,
-                intentFromApp.getBundleExtra(SuspendTestReceiver.EXTRA_SUSPENDED_APP_EXTRAS));
-        final PersistableBundle extras2 = getExtras("testMyPackageSuspendedOnChangingExtras", 2,
-                "2", 0.2);
-        suspendTestPackage(extras2, null, null);
-        intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
-        assertEquals("MY_PACKAGE_SUSPENDED delivery not reported",
-                ACTION_REPORT_MY_PACKAGE_SUSPENDED, intentFromApp.getAction());
-        assertSameExtras("Received app extras different to the updated extras", extras2,
-                intentFromApp.getBundleExtra(SuspendTestReceiver.EXTRA_SUSPENDED_APP_EXTRAS));
-    }
-
-    @Test
-    public void testCannotSuspendSelf() {
-        final String[] unchangedPkgs = mPackageManager.setPackagesSuspended(
-                new String[]{mContext.getOpPackageName()}, true, null, null,
-                (SuspendDialogInfo) null);
-        assertTrue(unchangedPkgs.length == 1);
-        assertEquals(mContext.getOpPackageName(), unchangedPkgs[0]);
-    }
-
-    @Test
-    public void testActivityStoppedOnSuspend() {
-        mAppCommsReceiver.register(mReceiverHandler, ACTION_REPORT_TEST_ACTIVITY_STARTED,
-                ACTION_REPORT_TEST_ACTIVITY_STOPPED);
-        startTestAppActivity();
-        Intent intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
-        assertEquals("Test activity start not reported",
-                ACTION_REPORT_TEST_ACTIVITY_STARTED, intentFromApp.getAction());
-        suspendTestPackage(null, null, null);
-        intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
-        assertEquals("Test activity stop not reported on suspending the test app",
-                ACTION_REPORT_TEST_ACTIVITY_STOPPED, intentFromApp.getAction());
-    }
-
-    @Test
     public void testGetLauncherExtrasNonNull() {
         final Bundle extrasWhenUnsuspended = mLauncherApps.getSuspendedPackageLauncherExtras(
                 TEST_APP_PACKAGE_NAME, mContext.getUser());
@@ -383,14 +178,15 @@
     public void testOnPackagesSuspendedNewAndOld() throws InterruptedException {
         final PersistableBundle suppliedExtras = getExtras(
                 "testOnPackagesSuspendedNewAndOld", 2, "2", 0.2);
-        final AtomicReference<String> overridingBothCallbackResult = new AtomicReference<>("");
-        final CountDownLatch twoCallbackLatch = new CountDownLatch(2);
+        final AtomicReference<String> error = new AtomicReference<>("");
+        final CountDownLatch rightCallbackLatch = new CountDownLatch(1);
+        final CountDownLatch wrongCallbackLatch = new CountDownLatch(1);
         mTestCallback = new StubbedCallback() {
             @Override
             public void onPackagesSuspended(String[] packageNames, UserHandle user) {
-                overridingBothCallbackResult.set(overridingBothCallbackResult.get()
+                error.set(error.get()
                         + "Old callback called even when the new one is overriden. ");
-                twoCallbackLatch.countDown();
+                wrongCallbackLatch.countDown();
             }
 
             @Override
@@ -411,17 +207,16 @@
                     errorString.append("Unexpected launcherExtras, supplied: " + suppliedExtras
                             + ", received: " + launcherExtras + ". ");
                 }
-                overridingBothCallbackResult.set(overridingBothCallbackResult.get()
+                error.set(error.get()
                         + errorString.toString());
-                twoCallbackLatch.countDown();
+                rightCallbackLatch.countDown();
             }
         };
         mLauncherApps.registerCallback(mTestCallback, mReceiverHandler);
         suspendTestPackage(null, suppliedExtras, null);
-        assertFalse("Both callbacks were invoked", twoCallbackLatch.await(5, TimeUnit.SECONDS));
-        twoCallbackLatch.countDown();
-        assertTrue("No callback was invoked", twoCallbackLatch.await(2, TimeUnit.SECONDS));
-        final String result = overridingBothCallbackResult.get();
+        assertFalse("Wrong callback was invoked", wrongCallbackLatch.await(5, TimeUnit.SECONDS));
+        assertTrue("Right callback wasn't invoked", rightCallbackLatch.await(2, TimeUnit.SECONDS));
+        final String result = error.get();
         assertTrue("Callbacks did not complete as expected: " + result, result.isEmpty());
     }
 
@@ -457,103 +252,6 @@
         assertTrue("Callback did not complete as expected: " + result, result.isEmpty());
     }
 
-    private void turnScreenOn() throws Exception {
-        if (!mUiDevice.isScreenOn()) {
-            mUiDevice.wakeUp();
-        }
-        final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
-        wm.dismissKeyguard(null, null);
-    }
-
-    @Test
-    public void testInterceptorActivity() throws Exception {
-        turnScreenOn();
-        mAppCommsReceiver.register(mReceiverHandler, ACTION_REPORT_MORE_DETAILS_ACTIVITY_STARTED,
-                ACTION_REPORT_TEST_ACTIVITY_STARTED);
-        final String testMessage = "This is a test message to report suspension of %1$s";
-        suspendTestPackage(null, null,
-                new SuspendDialogInfo.Builder().setMessage(testMessage).build());
-        startTestAppActivity();
-        assertNull("No broadcast was expected from app", mAppCommsReceiver.pollForIntent(2));
-        assertNotNull("Given dialog message not shown", mUiDevice.wait(
-                Until.findObject(By.text(String.format(testMessage, TEST_APP_LABEL))), 5000));
-        final String buttonText = mContext.getResources().getString(Resources.getSystem()
-                .getIdentifier("app_suspended_more_details", "string", "android"));
-        final UiObject2 moreDetailsButton = mUiDevice.findObject(
-                By.clickable(true).text(buttonText));
-        assertNotNull(buttonText + " button not shown", moreDetailsButton);
-        moreDetailsButton.click();
-        final Intent intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
-        assertEquals(buttonText + " activity start not reported",
-                ACTION_REPORT_MORE_DETAILS_ACTIVITY_STARTED, intentFromApp.getAction());
-        final String receivedPackageName = intentFromApp.getStringExtra(
-                EXTRA_RECEIVED_PACKAGE_NAME);
-        assertEquals("Wrong package name received by " + buttonText + " activity",
-                TEST_APP_PACKAGE_NAME, receivedPackageName);
-    }
-
-    private boolean setProfileOwner() throws IOException {
-        final String result = mUiDevice.executeShellCommand("dpm set-profile-owner --user cur "
-                + mDeviceAdminComponent.flattenToString());
-        return mPoSet = result.trim().startsWith("Success");
-    }
-
-    private boolean setDeviceOwner() throws IOException {
-        final String result = mUiDevice.executeShellCommand("dpm set-device-owner --user cur "
-                + mDeviceAdminComponent.flattenToString());
-        return mDoSet = result.trim().startsWith("Success");
-    }
-
-    private void removeProfileOrDeviceOwner() throws IOException {
-        if (mPoSet || mDoSet) {
-            mUiDevice.executeShellCommand("dpm remove-active-admin --user cur "
-                    + mDeviceAdminComponent.flattenToString());
-            mPoSet = mDoSet = false;
-        }
-    }
-
-    @Test
-    public void testCanSuspendWhenProfileOwner() throws IOException {
-        assumeTrue(mPackageManager.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN));
-        assertTrue("Profile-owner could not be set", setProfileOwner());
-        suspendTestPackage(null, null, null);
-    }
-
-    @Test
-    public void testCanSuspendWhenDeviceOwner() throws IOException {
-        assumeTrue(mPackageManager.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN));
-        assertTrue("Device-owner could not be set", setDeviceOwner());
-        suspendTestPackage(null, null, null);
-    }
-
-    @Test
-    public void testPackageUnsuspendedOnAddingDeviceOwner() throws IOException {
-        assumeTrue(mPackageManager.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN));
-        mAppCommsReceiver.register(mReceiverHandler, ACTION_REPORT_MY_PACKAGE_UNSUSPENDED,
-                ACTION_REPORT_MY_PACKAGE_SUSPENDED);
-        mAppCommsReceiver.drainPendingBroadcasts();
-        suspendTestPackage(null, null, null);
-        Intent intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
-        assertEquals(ACTION_REPORT_MY_PACKAGE_SUSPENDED, intentFromApp.getAction());
-        assertTrue("Device-owner could not be set", setDeviceOwner());
-        intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
-        assertEquals(ACTION_REPORT_MY_PACKAGE_UNSUSPENDED, intentFromApp.getAction());
-    }
-
-    @Test
-    public void testPackageUnsuspendedOnAddingProfileOwner() throws IOException {
-        assumeTrue(mPackageManager.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN));
-        mAppCommsReceiver.register(mReceiverHandler, ACTION_REPORT_MY_PACKAGE_UNSUSPENDED,
-                ACTION_REPORT_MY_PACKAGE_SUSPENDED);
-        mAppCommsReceiver.drainPendingBroadcasts();
-        suspendTestPackage(null, null, null);
-        Intent intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
-        assertEquals(ACTION_REPORT_MY_PACKAGE_SUSPENDED, intentFromApp.getAction());
-        assertTrue("Profile-owner could not be set", setProfileOwner());
-        intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
-        assertEquals(ACTION_REPORT_MY_PACKAGE_UNSUSPENDED, intentFromApp.getAction());
-    }
-
     @Test
     public void testCameraBlockedOnSuspend() throws Exception {
         assertOpBlockedOnSuspend(OP_CAMERA);
@@ -596,13 +294,9 @@
 
     @After
     public void tearDown() throws IOException {
-        mAppCommsReceiver.unregister();
         if (mTestCallback != null) {
             mLauncherApps.unregisterCallback(mTestCallback);
         }
-        removeProfileOrDeviceOwner();
-        mContext.sendBroadcast(new Intent(ACTION_FINISH_TEST_ACTIVITY)
-                .setPackage(TEST_APP_PACKAGE_NAME));
     }
 
     private static abstract class StubbedCallback extends LauncherApps.Callback {
diff --git a/services/tests/servicestests/src/com/android/server/statusbar/StatusBarManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/statusbar/StatusBarManagerServiceTest.java
index c293b5e..d164d2a 100644
--- a/services/tests/servicestests/src/com/android/server/statusbar/StatusBarManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/statusbar/StatusBarManagerServiceTest.java
@@ -21,6 +21,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.nullable;
 import static org.mockito.Mockito.any;
@@ -575,6 +576,30 @@
         }
     }
 
+    @Test
+    public void testSetNavBarModeOverride_setsOverrideModeKids() {
+        int navBarModeOverrideKids = StatusBarManager.NAV_BAR_MODE_OVERRIDE_KIDS;
+        mStatusBarManagerService.setNavBarModeOverride(navBarModeOverrideKids);
+
+        assertEquals(navBarModeOverrideKids, mStatusBarManagerService.getNavBarModeOverride());
+    }
+
+    @Test
+    public void testSetNavBarModeOverride_setsOverrideModeNone() {
+        int navBarModeOverrideNone = StatusBarManager.NAV_BAR_MODE_OVERRIDE_NONE;
+        mStatusBarManagerService.setNavBarModeOverride(navBarModeOverrideNone);
+
+        assertEquals(navBarModeOverrideNone, mStatusBarManagerService.getNavBarModeOverride());
+    }
+
+    @Test
+    public void testSetNavBarModeOverride_invalidInputThrowsError() {
+        int navBarModeOverrideInvalid = -1;
+
+        assertThrows(UnsupportedOperationException.class,
+                () -> mStatusBarManagerService.setNavBarModeOverride(navBarModeOverrideInvalid));
+    }
+
     private void mockUidCheck() {
         mockUidCheck(TEST_PACKAGE);
     }
diff --git a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
index add4cda..eeaf781 100644
--- a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
@@ -357,13 +357,13 @@
 
     /**
      * Tests that readPermissions works correctly for a library using the new
-     * {@code updatable-library} tag.
+     * {@code apex-library} tag.
      */
     @Test
     public void readPermissions_allowLibs_parsesUpdatableLibrary() throws IOException {
         String contents =
                 "<permissions>\n"
-                        + "    <updatable-library \n"
+                        + "    <apex-library \n"
                         + "        name=\"foo\"\n"
                         + "        file=\"" + mFooJar + "\"\n"
                         + "        on-bootclasspath-before=\"10\"\n"
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 62a0dd4..419dda5 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -62,6 +62,7 @@
 import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ONGOING;
 import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE;
 import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL;
+import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -5482,6 +5483,39 @@
     }
 
     @Test
+    public void testRateLimitedToasts_windowsRemoved() throws Exception {
+        final String testPackage = "testPackageName";
+        assertEquals(0, mService.mToastQueue.size());
+        mService.isSystemUid = false;
+        setToastRateIsWithinQuota(false); // rate limit reached
+        setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);
+        setAppInForegroundForToasts(mUid, false);
+
+        // package is not suspended
+        when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
+                .thenReturn(false);
+
+        Binder token = new Binder();
+        INotificationManager nmService = (INotificationManager) mService.mService;
+
+        nmService.enqueueTextToast(testPackage, token, "Text", 2000, 0, null);
+
+        // window token was added when enqueued
+        ArgumentCaptor<Binder> binderCaptor =
+                ArgumentCaptor.forClass(Binder.class);
+        verify(mWindowManagerInternal).addWindowToken(binderCaptor.capture(),
+                eq(TYPE_TOAST), anyInt(), eq(null));
+
+        // but never shown
+        verify(mStatusBar, times(0))
+                .showToast(anyInt(), any(), any(), any(), any(), anyInt(), any());
+
+        // and removed when rate limited
+        verify(mWindowManagerInternal)
+                .removeWindowToken(eq(binderCaptor.getValue()), eq(true), anyInt());
+    }
+
+    @Test
     public void backgroundSystemCustomToast_callsSetProcessImportantAsForegroundForToast() throws
             Exception {
         final String testPackage = "testPackageName";
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 2e62286..8a057f7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -2311,17 +2311,15 @@
 
         // Set initial orientation and update.
         activity.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
-        mDisplayContent.updateOrientation(
-                mDisplayContent.getRequestedOverrideConfiguration(),
-                null /* freezeThisOneIfNeeded */, false /* forceUpdate */);
+        mDisplayContent.updateOrientation(null /* freezeThisOneIfNeeded */,
+                false /* forceUpdate */);
         assertEquals(SCREEN_ORIENTATION_LANDSCAPE, mDisplayContent.getLastOrientation());
         appWindow.mResizeReported = false;
 
         // Update the orientation to perform 180 degree rotation and check that resize was reported.
         activity.setOrientation(SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
-        mDisplayContent.updateOrientation(
-                mDisplayContent.getRequestedOverrideConfiguration(),
-                null /* freezeThisOneIfNeeded */, false /* forceUpdate */);
+        mDisplayContent.updateOrientation(null /* freezeThisOneIfNeeded */,
+                false /* forceUpdate */);
         // In this test, DC will not get config update. Set the waiting flag to false.
         mDisplayContent.mWaitingForConfig = false;
         mWm.mRoot.performSurfacePlacement();
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 5062706..0d67946 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
@@ -678,6 +678,66 @@
                         opening, closing, false /* visible */));
     }
 
+    @Test
+    public void testGetAnimationTargets_embeddedTask() {
+        // [DisplayContent] -+- [Task1] -            [ActivityRecord1] (opening, invisible)
+        //                   +- [Task2] (embedded) - [ActivityRecord2] (opening, invisible)
+        final ActivityRecord activity1 = createActivityRecord(mDisplayContent);
+        activity1.setVisible(false);
+        activity1.mVisibleRequested = true;
+
+        final Task task2 = createTask(mDisplayContent);
+        task2.mRemoveWithTaskOrganizer = true;
+        final ActivityRecord activity2 = createActivityRecord(task2);
+        activity2.setVisible(false);
+        activity2.mVisibleRequested = true;
+
+        final ArraySet<ActivityRecord> opening = new ArraySet<>();
+        opening.add(activity1);
+        opening.add(activity2);
+        final ArraySet<ActivityRecord> closing = new ArraySet<>();
+
+        // No animation on the embedded task.
+        assertEquals(
+                new ArraySet<>(new WindowContainer[]{activity1.getTask()}),
+                AppTransitionController.getAnimationTargets(
+                        opening, closing, true /* visible */));
+        assertEquals(
+                new ArraySet<>(),
+                AppTransitionController.getAnimationTargets(
+                        opening, closing, false /* visible */));
+    }
+
+
+    @Test
+    public void testGetAnimationTargets_activityInEmbeddedTask() {
+        // [DisplayContent] - [Task] (embedded)-+- [ActivityRecord1] (opening, invisible)
+        //                                      +- [ActivityRecord2] (closing, visible)
+        final Task task = createTask(mDisplayContent);
+        task.mRemoveWithTaskOrganizer = true;
+
+        final ActivityRecord activity1 = createActivityRecord(task);
+        activity1.setVisible(false);
+        activity1.mVisibleRequested = true;
+        final ActivityRecord activity2 = createActivityRecord(task);
+
+        final ArraySet<ActivityRecord> opening = new ArraySet<>();
+        opening.add(activity1);
+        final ArraySet<ActivityRecord> closing = new ArraySet<>();
+        closing.add(activity2);
+
+        // Even though embedded task itself doesn't animate, activities in an embedded task
+        // animate.
+        assertEquals(
+                new ArraySet<>(new WindowContainer[]{activity1}),
+                AppTransitionController.getAnimationTargets(
+                        opening, closing, true /* visible */));
+        assertEquals(
+                new ArraySet<>(new WindowContainer[]{activity2}),
+                AppTransitionController.getAnimationTargets(
+                        opening, closing, false /* visible */));
+    }
+
     static class TestRemoteAnimationRunner implements IRemoteAnimationRunner {
         @Override
         public void onAnimationStart(int transit, RemoteAnimationTarget[] apps,
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 dc0e028..2ef59f6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -1422,18 +1422,16 @@
         assertEquals(config90.orientation, app.getConfiguration().orientation);
         assertEquals(config90.windowConfiguration.getBounds(), app.getBounds());
 
-        // Make wallaper laid out with the fixed rotation transform.
+        // Associate wallpaper with the fixed rotation transform.
         final WindowToken wallpaperToken = mWallpaperWindow.mToken;
         wallpaperToken.linkFixedRotationTransform(app);
-        mWallpaperWindow.mLayoutNeeded = true;
-        performLayout(mDisplayContent);
 
         // Force the negative offset to verify it can be updated.
         mWallpaperWindow.mXOffset = mWallpaperWindow.mYOffset = -1;
         assertTrue(mDisplayContent.mWallpaperController.updateWallpaperOffset(mWallpaperWindow,
                 false /* sync */));
-        assertThat(mWallpaperWindow.mXOffset).isGreaterThan(-1);
-        assertThat(mWallpaperWindow.mYOffset).isGreaterThan(-1);
+        assertThat(mWallpaperWindow.mXOffset).isNotEqualTo(-1);
+        assertThat(mWallpaperWindow.mYOffset).isNotEqualTo(-1);
 
         // The wallpaper need to animate with transformed position, so its surface position should
         // not be reset.
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
index af45b80..acf6dc5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
@@ -22,18 +22,9 @@
 import static android.view.InsetsState.ITYPE_STATUS_BAR;
 import static android.view.InsetsState.ITYPE_TOP_GESTURES;
 import static android.view.Surface.ROTATION_0;
-import static android.view.Surface.ROTATION_270;
 import static android.view.Surface.ROTATION_90;
 import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
-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.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
-import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;
-import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME;
-import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL;
 
@@ -56,11 +47,8 @@
 import android.view.DisplayCutout;
 import android.view.DisplayInfo;
 import android.view.InsetsState;
-import android.view.InsetsVisibilities;
 import android.view.PrivacyIndicatorBounds;
 import android.view.RoundedCorners;
-import android.view.WindowInsets.Side;
-import android.view.WindowInsets.Type;
 
 import androidx.test.filters.SmallTest;
 
@@ -108,15 +96,6 @@
         updateDisplayFrames();
     }
 
-    void addWindowWithRawInsetsState(WindowState win) {
-        addWindow(win);
-        // Without mPerformLayout in display content, the window cannot see any insets. Override the
-        // insets state with the global one.
-        final InsetsState insetsState =
-                win.getDisplayContent().getInsetsStateController().getRawInsetsState();
-        win.mAboveInsetsState.set(insetsState);
-    }
-
     public void setRotation(int rotation, boolean includingWindows) {
         mRotation = rotation;
         updateDisplayFrames();
@@ -232,388 +211,6 @@
     }
 
     @Test
-    public void layoutWindowLw_fitStatusBars() {
-        mWindow.mAttrs.setFitInsetsTypes(Type.statusBars());
-        addWindowWithRawInsetsState(mWindow);
-
-        mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-
-        assertInsetByTopBottom(mWindow.getDisplayFrame(), STATUS_BAR_HEIGHT, 0);
-        assertInsetByTopBottom(mWindow.getParentFrame(), STATUS_BAR_HEIGHT, 0);
-    }
-
-    @Test
-    public void layoutWindowLw_fitNavigationBars() {
-        mWindow.mAttrs.setFitInsetsTypes(Type.navigationBars());
-        addWindowWithRawInsetsState(mWindow);
-
-        mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-
-        assertInsetByTopBottom(mWindow.getDisplayFrame(), 0, NAV_BAR_HEIGHT);
-        assertInsetByTopBottom(mWindow.getParentFrame(), 0, NAV_BAR_HEIGHT);
-    }
-
-    @Test
-    public void layoutWindowLw_fitAllSides() {
-        mWindow.mAttrs.setFitInsetsSides(Side.all());
-        addWindowWithRawInsetsState(mWindow);
-
-        mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-
-        assertInsetByTopBottom(mWindow.getDisplayFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
-        assertInsetByTopBottom(mWindow.getParentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
-    }
-
-    @Test
-    public void layoutWindowLw_fitTopOnly() {
-        mWindow.mAttrs.setFitInsetsSides(Side.TOP);
-        addWindowWithRawInsetsState(mWindow);
-
-        mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-
-        assertInsetByTopBottom(mWindow.getDisplayFrame(), STATUS_BAR_HEIGHT, 0);
-        assertInsetByTopBottom(mWindow.getParentFrame(), STATUS_BAR_HEIGHT, 0);
-    }
-
-    @Test
-    public void layoutWindowLw_fitInsetsIgnoringVisibility() {
-        final InsetsState state =
-                mDisplayContent.getInsetsStateController().getRawInsetsState();
-        state.getSource(InsetsState.ITYPE_STATUS_BAR).setVisible(false);
-        state.getSource(InsetsState.ITYPE_NAVIGATION_BAR).setVisible(false);
-        mWindow.mAttrs.setFitInsetsIgnoringVisibility(true);
-        addWindowWithRawInsetsState(mWindow);
-
-        mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-
-        assertInsetByTopBottom(mWindow.getDisplayFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
-        assertInsetByTopBottom(mWindow.getParentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
-    }
-
-    @Test
-    public void layoutWindowLw_fitInsetsNotIgnoringVisibility() {
-        final InsetsState state =
-                mDisplayContent.getInsetsStateController().getRawInsetsState();
-        state.getSource(InsetsState.ITYPE_STATUS_BAR).setVisible(false);
-        state.getSource(InsetsState.ITYPE_NAVIGATION_BAR).setVisible(false);
-        mWindow.mAttrs.setFitInsetsIgnoringVisibility(false);
-        addWindowWithRawInsetsState(mWindow);
-
-        mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-
-        assertInsetByTopBottom(mWindow.getDisplayFrame(), 0, 0);
-        assertInsetByTopBottom(mWindow.getParentFrame(), 0, 0);
-    }
-
-    @Test
-    public void layoutWindowLw_insetParentFrameByIme() {
-        final InsetsState state =
-                mDisplayContent.getInsetsStateController().getRawInsetsState();
-        state.getSource(InsetsState.ITYPE_IME).setVisible(true);
-        state.getSource(InsetsState.ITYPE_IME).setFrame(
-                0, DISPLAY_HEIGHT - IME_HEIGHT, DISPLAY_WIDTH, DISPLAY_HEIGHT);
-        mWindow.mAttrs.privateFlags |= PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME;
-        addWindowWithRawInsetsState(mWindow);
-
-        mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-
-        assertInsetByTopBottom(mWindow.getDisplayFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
-        assertInsetByTopBottom(mWindow.getParentFrame(), STATUS_BAR_HEIGHT, IME_HEIGHT);
-    }
-
-    @Test
-    public void layoutWindowLw_fitDisplayCutout() {
-        addDisplayCutout();
-
-        mWindow.mAttrs.setFitInsetsTypes(Type.displayCutout());
-        mWindow.mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
-        addWindowWithRawInsetsState(mWindow);
-
-        mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-
-        assertInsetByTopBottom(mWindow.getDisplayFrame(), DISPLAY_CUTOUT_HEIGHT, 0);
-        assertInsetByTopBottom(mWindow.getParentFrame(), DISPLAY_CUTOUT_HEIGHT, 0);
-    }
-
-    @Test
-    public void layoutWindowLw_withDisplayCutout() {
-        addDisplayCutout();
-
-        mWindow.mAttrs.flags =
-                FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
-        mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
-        addWindowWithRawInsetsState(mWindow);
-
-        mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-
-        assertInsetByTopBottom(mWindow.getParentFrame(), 0, 0);
-        assertInsetByTopBottom(mWindow.getDisplayFrame(), 0, 0);
-    }
-
-    @Test
-    public void layoutWindowLw_withDisplayCutout_never() {
-        addDisplayCutout();
-
-        mWindow.mAttrs.flags =
-                FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
-        mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
-        mWindow.mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;
-        addWindowWithRawInsetsState(mWindow);
-
-        mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-
-        assertInsetByTopBottom(mWindow.getParentFrame(), STATUS_BAR_HEIGHT, 0);
-        assertInsetByTopBottom(mWindow.getDisplayFrame(), STATUS_BAR_HEIGHT, 0);
-    }
-
-    @Test
-    public void layoutWindowLw_withDisplayCutout_shortEdges() {
-        addDisplayCutout();
-
-        mWindow.mAttrs.flags =
-                FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
-        mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
-        mWindow.mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
-        addWindowWithRawInsetsState(mWindow);
-
-        mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-
-        assertInsetBy(mWindow.getParentFrame(), 0, 0, 0, 0);
-        assertInsetBy(mWindow.getDisplayFrame(), 0, 0, 0, 0);
-    }
-
-    @Test
-    public void layoutWindowLw_withDisplayCutout_always() {
-        addDisplayCutout();
-
-        mWindow.mAttrs.flags =
-                FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
-        mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
-        mWindow.mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
-        addWindowWithRawInsetsState(mWindow);
-
-        mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-
-        assertInsetBy(mWindow.getParentFrame(), 0, 0, 0, 0);
-        assertInsetBy(mWindow.getDisplayFrame(), 0, 0, 0, 0);
-    }
-
-    @Test
-    public void layoutWindowLw_withDisplayCutout_layoutFullscreen() {
-        addDisplayCutout();
-
-        mWindow.mAttrs.flags =
-                FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
-        mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
-        addWindowWithRawInsetsState(mWindow);
-
-        mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-
-        assertInsetByTopBottom(mWindow.getParentFrame(), 0, 0);
-        assertInsetByTopBottom(mWindow.getDisplayFrame(), 0, 0);
-    }
-
-    @Test
-    public void layoutWindowLw_withDisplayCutout_fullscreen() {
-        addDisplayCutout();
-
-        mWindow.mAttrs.flags =
-                FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
-        mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
-        mDisplayContent.getInsetsStateController().getRawInsetsState()
-                .getSource(InsetsState.ITYPE_STATUS_BAR).setVisible(false);
-        final InsetsVisibilities requestedVisibilities = new InsetsVisibilities();
-        requestedVisibilities.setVisibility(ITYPE_STATUS_BAR, false);
-        mWindow.setRequestedVisibilities(requestedVisibilities);
-        addWindowWithRawInsetsState(mWindow);
-
-        mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-
-        assertInsetByTopBottom(mWindow.getParentFrame(), STATUS_BAR_HEIGHT, 0);
-        assertInsetByTopBottom(mWindow.getDisplayFrame(), STATUS_BAR_HEIGHT, 0);
-    }
-
-    @Test
-    public void layoutWindowLw_withDisplayCutout_fullscreenInCutout() {
-        addDisplayCutout();
-
-        mWindow.mAttrs.flags =
-                FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
-        mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
-        mDisplayContent.getInsetsStateController().getRawInsetsState()
-                .getSource(InsetsState.ITYPE_STATUS_BAR).setVisible(false);
-        final InsetsVisibilities requestedVisibilities = new InsetsVisibilities();
-        requestedVisibilities.setVisibility(ITYPE_STATUS_BAR, false);
-        mWindow.setRequestedVisibilities(requestedVisibilities);
-        mWindow.mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
-        addWindowWithRawInsetsState(mWindow);
-
-        mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-
-        assertInsetByTopBottom(mWindow.getParentFrame(), 0, 0);
-        assertInsetByTopBottom(mWindow.getDisplayFrame(), 0, 0);
-    }
-
-
-    @Test
-    public void layoutWindowLw_withDisplayCutout_landscape() {
-        addDisplayCutout();
-        setRotation(ROTATION_90, true /* includingWindows */);
-        mWindow.mAttrs.flags =
-                FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
-        mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
-        addWindowWithRawInsetsState(mWindow);
-
-        mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-
-        assertInsetBy(mWindow.getParentFrame(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
-        assertInsetBy(mWindow.getDisplayFrame(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
-    }
-
-    @Test
-    public void layoutWindowLw_withDisplayCutout_seascape() {
-        addDisplayCutout();
-        setRotation(ROTATION_270, true /* includingWindows */);
-
-        mWindow.mAttrs.flags =
-                FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
-        mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
-        addWindowWithRawInsetsState(mWindow);
-
-        mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-
-        assertInsetBy(mWindow.getParentFrame(), 0, 0, DISPLAY_CUTOUT_HEIGHT, 0);
-        assertInsetBy(mWindow.getDisplayFrame(), 0, 0, DISPLAY_CUTOUT_HEIGHT, 0);
-    }
-
-    @Test
-    public void layoutWindowLw_withDisplayCutout_fullscreen_landscape() {
-        addDisplayCutout();
-        setRotation(ROTATION_90, true /* includingWindows */);
-
-        mWindow.mAttrs.flags =
-                FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
-        mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
-        addWindowWithRawInsetsState(mWindow);
-
-        mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-
-        assertInsetBy(mWindow.getParentFrame(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
-    }
-
-    @Test
-    public void layoutWindowLw_withDisplayCutout_floatingInScreen() {
-        addDisplayCutout();
-
-        mWindow.mAttrs.flags = FLAG_LAYOUT_IN_SCREEN;
-        mWindow.mAttrs.setFitInsetsTypes(Type.systemBars() & ~Type.statusBars());
-        mWindow.mAttrs.type = TYPE_APPLICATION_OVERLAY;
-        mWindow.mAttrs.width = DISPLAY_WIDTH;
-        mWindow.mAttrs.height = DISPLAY_HEIGHT;
-        addWindowWithRawInsetsState(mWindow);
-
-        mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-
-        assertInsetByTopBottom(mWindow.getParentFrame(), 0, NAV_BAR_HEIGHT);
-        assertInsetByTopBottom(mWindow.getDisplayFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
-    }
-
-    @Test
-    public void layoutWindowLw_withDisplayCutout_fullscreenInCutout_landscape() {
-        addDisplayCutout();
-        setRotation(ROTATION_90, true /* includingWindows */);
-
-        mWindow.mAttrs.flags =
-                FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
-        mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
-        mWindow.mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
-        addWindowWithRawInsetsState(mWindow);
-
-        mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-
-        assertInsetBy(mWindow.getParentFrame(), 0, 0, 0, 0);
-    }
-
-    @Test
-    public void layoutWindowLw_withLongEdgeDisplayCutout() {
-        addLongEdgeDisplayCutout();
-
-        mWindow.mAttrs.flags =
-                FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
-        mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
-        addWindowWithRawInsetsState(mWindow);
-
-        mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-
-        assertInsetBy(mWindow.getParentFrame(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
-        assertInsetBy(mWindow.getDisplayFrame(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
-    }
-
-    @Test
-    public void layoutWindowLw_withLongEdgeDisplayCutout_never() {
-        addLongEdgeDisplayCutout();
-
-        mWindow.mAttrs.flags =
-                FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
-        mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
-        mWindow.mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;
-        addWindowWithRawInsetsState(mWindow);
-
-        mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-
-        assertInsetBy(mWindow.getParentFrame(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
-        assertInsetBy(mWindow.getDisplayFrame(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
-    }
-
-    @Test
-    public void layoutWindowLw_withLongEdgeDisplayCutout_shortEdges() {
-        addLongEdgeDisplayCutout();
-
-        mWindow.mAttrs.flags =
-                FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
-        mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
-        mWindow.mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
-        addWindowWithRawInsetsState(mWindow);
-
-        mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-
-        assertInsetBy(mWindow.getParentFrame(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
-        assertInsetBy(mWindow.getDisplayFrame(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
-    }
-
-    @Test
-    public void layoutWindowLw_withLongEdgeDisplayCutout_always() {
-        addLongEdgeDisplayCutout();
-
-        mWindow.mAttrs.flags =
-                FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
-        mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
-        mWindow.mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
-        addWindowWithRawInsetsState(mWindow);
-
-        mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-
-        assertInsetBy(mWindow.getParentFrame(), 0, 0, 0, 0);
-        assertInsetBy(mWindow.getDisplayFrame(), 0, 0, 0, 0);
-    }
-
-    @Test
-    public void layoutWindowLw_withForwardInset_SoftInputAdjustNothing() {
-        mWindow.mAttrs.flags =
-                FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
-        mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
-        mWindow.mAttrs.softInputMode = SOFT_INPUT_ADJUST_NOTHING;
-        addWindowWithRawInsetsState(mWindow);
-
-        final int forwardedInsetBottom = 50;
-        mDisplayPolicy.setForwardedInsets(Insets.of(0, 0, 0, forwardedInsetBottom));
-        mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-
-        assertInsetBy(mWindow.getParentFrame(), 0, 0, 0, 0);
-        assertInsetBy(mWindow.getDisplayFrame(), 0, 0, 0, 0);
-    }
-
-    @Test
     public void layoutHint_appWindow() {
         mWindow.mAttrs.setFitInsetsTypes(0);
 
@@ -691,22 +288,4 @@
         assertEquals(DISPLAY_WIDTH, frame.width());
         assertEquals(DISPLAY_HEIGHT, rotatedFrame.width());
     }
-
-    /**
-     * Asserts that {@code actual} is inset by the given amounts from the full display rect.
-     *
-     * Convenience wrapper for when only the top and bottom inset are non-zero.
-     */
-    private void assertInsetByTopBottom(Rect actual, int expectedInsetTop,
-            int expectedInsetBottom) {
-        assertInsetBy(actual, 0, expectedInsetTop, 0, expectedInsetBottom);
-    }
-
-    /** Asserts that {@code actual} is inset by the given amounts from the full display rect. */
-    private void assertInsetBy(Rect actual, int expectedInsetLeft, int expectedInsetTop,
-            int expectedInsetRight, int expectedInsetBottom) {
-        assertEquals(new Rect(expectedInsetLeft, expectedInsetTop,
-                mFrames.mDisplayWidth - expectedInsetRight,
-                mFrames.mDisplayHeight - expectedInsetBottom), actual);
-    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
index 8da8596..6970005 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
@@ -189,11 +189,6 @@
         assertEquals(0,
                 displayPolicy.updateLightNavigationBarLw(APPEARANCE_LIGHT_NAVIGATION_BARS, null));
 
-        // Dimming window clears APPEARANCE_LIGHT_NAVIGATION_BARS.
-        assertEquals(0, displayPolicy.updateLightNavigationBarLw(0, dimming));
-        assertEquals(0, displayPolicy.updateLightNavigationBarLw(
-                APPEARANCE_LIGHT_NAVIGATION_BARS, dimming));
-
         // Control window overrides APPEARANCE_LIGHT_NAVIGATION_BARS flag.
         assertEquals(0, displayPolicy.updateLightNavigationBarLw(0, opaqueDarkNavBar));
         assertEquals(0, displayPolicy.updateLightNavigationBarLw(
diff --git a/services/tests/wmtests/src/com/android/server/wm/SplashScreenExceptionListTest.java b/services/tests/wmtests/src/com/android/server/wm/SplashScreenExceptionListTest.java
index 3714d99..f5d915d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SplashScreenExceptionListTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SplashScreenExceptionListTest.java
@@ -39,6 +39,7 @@
 
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
 
 /**
  * Test for the splash screen exception list
@@ -55,7 +56,16 @@
     private DeviceConfig.Properties mInitialWindowManagerProperties;
     private final HandlerExecutor mExecutor = new HandlerExecutor(
             new Handler(Looper.getMainLooper()));
-    private final SplashScreenExceptionList mList = new SplashScreenExceptionList(mExecutor);
+    private final SplashScreenExceptionList mList = new SplashScreenExceptionList(mExecutor) {
+        @Override
+        void updateDeviceConfig(String rawList) {
+            super.updateDeviceConfig(rawList);
+            if (mOnUpdateDeviceConfig != null) {
+                mOnUpdateDeviceConfig.accept(rawList);
+            }
+        }
+    };
+    private Consumer<String> mOnUpdateDeviceConfig;
 
     @Before
     public void setUp() throws Exception {
@@ -91,13 +101,11 @@
 
     private void setExceptionListAndWaitForCallback(String commaSeparatedList) {
         CountDownLatch latch = new CountDownLatch(1);
-        DeviceConfig.OnPropertiesChangedListener onPropertiesChangedListener = (p) -> {
-            if (commaSeparatedList.equals(p.getString(KEY_SPLASH_SCREEN_EXCEPTION_LIST, null))) {
+        mOnUpdateDeviceConfig = rawList -> {
+            if (commaSeparatedList.equals(rawList)) {
                 latch.countDown();
             }
         };
-        DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
-                mExecutor, onPropertiesChangedListener);
         DeviceConfig.setProperty(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
                 KEY_SPLASH_SCREEN_EXCEPTION_LIST, commaSeparatedList, false);
         try {
@@ -105,8 +113,6 @@
                     latch.await(1, TimeUnit.SECONDS));
         } catch (InterruptedException e) {
             Assert.fail(e.getMessage());
-        } finally {
-            DeviceConfig.removeOnPropertiesChangedListener(onPropertiesChangedListener);
         }
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
index a1d0eb8..790b154 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
@@ -25,11 +25,10 @@
 import static com.android.server.wm.utils.CommonUtils.runWithShellPermissionIdentity;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
 
 import android.app.Activity;
+import android.app.ActivityManager.RunningTaskInfo;
 import android.app.ActivityManager.TaskDescription;
 import android.app.ActivityOptions;
 import android.app.ActivityTaskManager;
@@ -57,7 +56,6 @@
 import androidx.test.filters.MediumTest;
 
 import org.junit.After;
-import org.junit.Before;
 import org.junit.Test;
 
 import java.util.Arrays;
@@ -73,49 +71,42 @@
 @MediumTest
 public class TaskStackChangedListenerTest {
 
-    private static final int VIRTUAL_DISPLAY_WIDTH = 800;
-    private static final int VIRTUAL_DISPLAY_HEIGHT = 600;
-    private static final int VIRTUAL_DISPLAY_DENSITY = 160;
-
     private ITaskStackListener mTaskStackListener;
-    private DisplayManager mDisplayManager;
     private VirtualDisplay mVirtualDisplay;
+    private ImageReader mImageReader;
 
     private static final int WAIT_TIMEOUT_MS = 5000;
     private static final Object sLock = new Object();
 
-    @Before
-    public void setUp() {
-        mDisplayManager = getInstrumentation().getContext().getSystemService(
-                DisplayManager.class);
-        mVirtualDisplay = createVirtualDisplay(
-                getClass().getSimpleName() + "_virtualDisplay",
-                VIRTUAL_DISPLAY_WIDTH, VIRTUAL_DISPLAY_HEIGHT, VIRTUAL_DISPLAY_DENSITY);
-    }
-
     @After
     public void tearDown() throws Exception {
-        ActivityTaskManager.getService().unregisterTaskStackListener(mTaskStackListener);
-        mTaskStackListener = null;
-        mVirtualDisplay.release();
+        if (mTaskStackListener != null) {
+            ActivityTaskManager.getService().unregisterTaskStackListener(mTaskStackListener);
+        }
+        if (mVirtualDisplay != null) {
+            mVirtualDisplay.release();
+            mImageReader.close();
+        }
     }
 
-    private VirtualDisplay createVirtualDisplay(String name, int width, int height, int density) {
-        VirtualDisplay virtualDisplay = null;
-        try (ImageReader reader = ImageReader.newInstance(width, height,
-                /* format= */ PixelFormat.RGBA_8888, /* maxImages= */ 2)) {
-            int flags = VIRTUAL_DISPLAY_FLAG_PRESENTATION | VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY
-                    | VIRTUAL_DISPLAY_FLAG_PUBLIC;
-            virtualDisplay = mDisplayManager.createVirtualDisplay(
-                    name, width, height, density, reader.getSurface(), flags);
-            virtualDisplay.setSurface(reader.getSurface());
-        }
-        assertTrue("display id must be unique",
-                virtualDisplay.getDisplay().getDisplayId() != Display.DEFAULT_DISPLAY);
+    private VirtualDisplay createVirtualDisplay() {
+        final int width = 800;
+        final int height = 600;
+        final int density = 160;
+        final DisplayManager displayManager = getInstrumentation().getContext().getSystemService(
+                DisplayManager.class);
+        mImageReader = ImageReader.newInstance(width, height, PixelFormat.RGBA_8888,
+                2 /* maxImages */);
+        final int flags = VIRTUAL_DISPLAY_FLAG_PRESENTATION | VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY
+                | VIRTUAL_DISPLAY_FLAG_PUBLIC;
+        final String name = getClass().getSimpleName() + "_VirtualDisplay";
+        mVirtualDisplay = displayManager.createVirtualDisplay(name, width, height, density,
+                mImageReader.getSurface(), flags);
+        mVirtualDisplay.setSurface(mImageReader.getSurface());
         assertNotNull("display must be registered",
-                Arrays.asList(mDisplayManager.getDisplays()).stream().filter(
+                Arrays.stream(displayManager.getDisplays()).filter(
                         d -> d.getName().equals(name)).findAny());
-        return virtualDisplay;
+        return mVirtualDisplay;
     }
 
     @Test
@@ -163,11 +154,10 @@
                 mTaskId = taskId;
             }
             @Override
-            public void onTaskDescriptionChanged(int taskId, TaskDescription td)
-                    throws RemoteException {
-                if (mTaskId == taskId && !TextUtils.isEmpty(td.getLabel())) {
-                    params[0] = taskId;
-                    params[1] = td;
+            public void onTaskDescriptionChanged(RunningTaskInfo info) {
+                if (mTaskId == info.taskId && !TextUtils.isEmpty(info.taskDescription.getLabel())) {
+                    params[0] = info.taskId;
+                    params[1] = info.taskDescription;
                     latch.countDown();
                 }
             }
@@ -211,75 +201,71 @@
     @Test
     @Presubmit
     public void testTaskChangeCallBacks() throws Exception {
-        final Object[] params = new Object[2];
         final CountDownLatch taskCreatedLaunchLatch = new CountDownLatch(1);
         final CountDownLatch taskMovedToFrontLatch = new CountDownLatch(1);
         final CountDownLatch taskRemovedLatch = new CountDownLatch(1);
         final CountDownLatch taskRemovalStartedLatch = new CountDownLatch(1);
-        final CountDownLatch onDetachedFromWindowLatch = new CountDownLatch(1);
+        final int[] expectedTaskId = { -1 };
+        final int[] receivedTaskId = { -1 };
+        final ComponentName expectedName = new ComponentName(getInstrumentation().getContext(),
+                ActivityTaskChangeCallbacks.class);
         registerTaskStackChangedListener(new TaskStackListener() {
             @Override
-            public void onTaskCreated(int taskId, ComponentName componentName)
-                    throws RemoteException {
-                params[0] = taskId;
-                params[1] = componentName;
-                taskCreatedLaunchLatch.countDown();
+            public void onTaskCreated(int taskId, ComponentName componentName) {
+                receivedTaskId[0] = taskId;
+                if (expectedName.equals(componentName)) {
+                    taskCreatedLaunchLatch.countDown();
+                }
             }
 
             @Override
-            public void onTaskMovedToFront(int taskId) throws RemoteException {
-                params[0] = taskId;
+            public void onTaskMovedToFront(RunningTaskInfo info) {
+                receivedTaskId[0] = info.taskId;
                 taskMovedToFrontLatch.countDown();
             }
 
             @Override
-            public void onTaskRemovalStarted(int taskId) {
-                params[0] = taskId;
-                taskRemovalStartedLatch.countDown();
+            public void onTaskRemovalStarted(RunningTaskInfo info) {
+                if (expectedTaskId[0] == info.taskId) {
+                    taskRemovalStartedLatch.countDown();
+                }
             }
 
             @Override
-            public void onTaskRemoved(int taskId) throws RemoteException {
-                if (taskCreatedLaunchLatch.getCount() == 1) {
-                    // The test activity hasn't started. Ignore the noise from previous test.
-                    return;
+            public void onTaskRemoved(int taskId) {
+                if (expectedTaskId[0] == taskId) {
+                    taskRemovedLatch.countDown();
                 }
-                params[0] = taskId;
-                taskRemovedLatch.countDown();
             }
         });
 
         final ActivityTaskChangeCallbacks activity =
                 (ActivityTaskChangeCallbacks) startTestActivity(ActivityTaskChangeCallbacks.class);
-        activity.setDetachedFromWindowLatch(onDetachedFromWindowLatch);
-        final int id = activity.getTaskId();
+        expectedTaskId[0] = activity.getTaskId();
 
         // Test for onTaskCreated and onTaskMovedToFront
         waitForCallback(taskMovedToFrontLatch);
         assertEquals(0, taskCreatedLaunchLatch.getCount());
-        assertEquals(id, params[0]);
-        ComponentName componentName = (ComponentName) params[1];
-        assertEquals(ActivityTaskChangeCallbacks.class.getName(), componentName.getClassName());
+        assertEquals(expectedTaskId[0], receivedTaskId[0]);
 
+        // Ensure that the window is attached before removal so there will be a detached callback.
+        waitForCallback(activity.mOnAttachedToWindowCountDownLatch);
         // Test for onTaskRemovalStarted.
         assertEquals(1, taskRemovalStartedLatch.getCount());
         assertEquals(1, taskRemovedLatch.getCount());
         activity.finishAndRemoveTask();
         waitForCallback(taskRemovalStartedLatch);
         // onTaskRemovalStarted happens before the activity's window is removed.
-        assertFalse(activity.mOnDetachedFromWindowCalled);
-        assertEquals(id, params[0]);
+        assertEquals(1, activity.mOnDetachedFromWindowCountDownLatch.getCount());
 
         // Test for onTaskRemoved.
         waitForCallback(taskRemovedLatch);
-        assertEquals(id, params[0]);
-        waitForCallback(onDetachedFromWindowLatch);
-        assertTrue(activity.mOnDetachedFromWindowCalled);
+        waitForCallback(activity.mOnDetachedFromWindowCountDownLatch);
     }
 
     @Test
     public void testTaskDisplayChanged() throws Exception {
-        int virtualDisplayId = mVirtualDisplay.getDisplay().getDisplayId();
+        final int virtualDisplayId = createVirtualDisplay().getDisplay().getDisplayId();
 
         // Launch a Activity inside VirtualDisplay
         CountDownLatch displayChangedLatch1 = new CountDownLatch(1);
@@ -498,18 +484,18 @@
     }
 
     public static class ActivityTaskChangeCallbacks extends TestActivity {
-        public boolean mOnDetachedFromWindowCalled = false;
-        private CountDownLatch mOnDetachedFromWindowCountDownLatch;
+        final CountDownLatch mOnAttachedToWindowCountDownLatch = new CountDownLatch(1);
+        final CountDownLatch mOnDetachedFromWindowCountDownLatch = new CountDownLatch(1);
+
+        @Override
+        public void onAttachedToWindow() {
+            mOnAttachedToWindowCountDownLatch.countDown();
+        }
 
         @Override
         public void onDetachedFromWindow() {
-            mOnDetachedFromWindowCalled = true;
             mOnDetachedFromWindowCountDownLatch.countDown();
         }
-
-        void setDetachedFromWindowLatch(CountDownLatch countDownLatch) {
-            mOnDetachedFromWindowCountDownLatch = countDownLatch;
-        }
     }
 
     public static class ActivityInVirtualDisplay extends TestActivity {
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 a7a374b..fe41734 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
@@ -44,6 +44,7 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
 import static com.android.server.policy.WindowManagerPolicy.USER_ROTATION_FREE;
 import static com.android.server.wm.Task.FLAG_FORCE_HIDDEN_FOR_TASK_ORG;
+import static com.android.server.wm.TaskFragment.TASK_FRAGMENT_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -66,6 +67,7 @@
 import static org.mockito.Mockito.never;
 
 import android.app.ActivityManager;
+import android.app.ActivityOptions;
 import android.app.TaskInfo;
 import android.app.WindowConfiguration;
 import android.content.ComponentName;
@@ -899,22 +901,21 @@
 
     /**
      * Test that root activity index is reported correctly when looking for the 'effective root' in
-     * case when bottom activity is finishing. Ignore the relinquishing task identity if it's not a
-     * system activity even with the FLAG_RELINQUISH_TASK_IDENTITY.
+     * case when bottom activities are relinquishing task identity or finishing.
      */
     @Test
     public void testFindRootIndex_effectiveRoot_finishingAndRelinquishing() {
-        final Task task = getTestTask();
+        final ActivityRecord activity0 = new ActivityBuilder(mAtm).setCreateTask(true).build();
+        final Task task = activity0.getTask();
         // Add extra two activities. Mark the one on the bottom with "relinquishTaskIdentity" and
         // one above as finishing.
-        final ActivityRecord activity0 = task.getBottomMostActivity();
         activity0.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
         final ActivityRecord activity1 = new ActivityBuilder(mAtm).setTask(task).build();
         activity1.finishing = true;
         new ActivityBuilder(mAtm).setTask(task).build();
 
         assertEquals("The first non-finishing activity and non-relinquishing task identity "
-                + "must be reported.", task.getChildAt(0), task.getRootActivity(
+                + "must be reported.", task.getChildAt(2), task.getRootActivity(
                 false /*ignoreRelinquishIdentity*/, true /*setToBottomIfNone*/));
     }
 
@@ -934,21 +935,21 @@
     }
 
     /**
-     * Test that the root activity index is reported correctly when looking for the
-     * 'effective root' for the case when all non-system activities have relinquishTaskIdentity set.
+     * Test that the topmost activity index is reported correctly when looking for the
+     * 'effective root' for the case when all activities have relinquishTaskIdentity set.
      */
     @Test
     public void testFindRootIndex_effectiveRoot_relinquishingMultipleActivities() {
-        final Task task = getTestTask();
+        final ActivityRecord activity0 = new ActivityBuilder(mAtm).setCreateTask(true).build();
+        final Task task = activity0.getTask();
         // Set relinquishTaskIdentity for all activities in the task
-        final ActivityRecord activity0 = task.getBottomMostActivity();
         activity0.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
         final ActivityRecord activity1 = new ActivityBuilder(mAtm).setTask(task).build();
         activity1.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
 
-        assertEquals("The topmost activity in the task must be reported.", task.getChildAt(0),
-                task.getRootActivity(false /*ignoreRelinquishIdentity*/,
-                        true /*setToBottomIfNone*/));
+        assertEquals("The topmost activity in the task must be reported.",
+                task.getChildAt(task.getChildCount() - 1), task.getRootActivity(
+                        false /*ignoreRelinquishIdentity*/, true /*setToBottomIfNone*/));
     }
 
     /** Test that bottom-most activity is reported in {@link Task#getRootActivity()}. */
@@ -1086,14 +1087,14 @@
     }
 
     /**
-     * Test {@link ActivityRecord#getTaskForActivityLocked(IBinder, boolean)} with non-system
-     * activity that relinquishes task identity.
+     * Test {@link ActivityRecord#getTaskForActivityLocked(IBinder, boolean)} with activity that
+     * relinquishes task identity.
      */
     @Test
     public void testGetTaskForActivity_onlyRoot_relinquishTaskIdentity() {
-        final Task task = getTestTask();
+        final ActivityRecord activity0 = new ActivityBuilder(mAtm).setCreateTask(true).build();
+        final Task task = activity0.getTask();
         // Make the current root activity relinquish task identity
-        final ActivityRecord activity0 = task.getBottomMostActivity();
         activity0.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
         // Add an extra activity on top - this will be the new root
         final ActivityRecord activity1 = new ActivityBuilder(mAtm).setTask(task).build();
@@ -1102,7 +1103,7 @@
 
         assertEquals(task.mTaskId,
                 ActivityRecord.getTaskForActivityLocked(activity0.token, true /* onlyRoot */));
-        assertEquals("No task must be reported for activity that is above root", INVALID_TASK_ID,
+        assertEquals(task.mTaskId,
                 ActivityRecord.getTaskForActivityLocked(activity1.token, true /* onlyRoot */));
         assertEquals("No task must be reported for activity that is above root", INVALID_TASK_ID,
                 ActivityRecord.getTaskForActivityLocked(activity2.token, true /* onlyRoot */));
@@ -1189,6 +1190,46 @@
         verify(task).setIntent(eq(activity0));
     }
 
+    /**
+     * Test {@link Task#updateEffectiveIntent()} when activity with relinquishTaskIdentity but
+     * another with different uid. This should make the task use the root activity when updating the
+     * intent.
+     */
+    @Test
+    public void testUpdateEffectiveIntent_relinquishingWithDifferentUid() {
+        final ActivityRecord activity0 = new ActivityBuilder(mAtm)
+                .setActivityFlags(FLAG_RELINQUISH_TASK_IDENTITY).setCreateTask(true).build();
+        final Task task = activity0.getTask();
+
+        // Add an extra activity on top
+        new ActivityBuilder(mAtm).setUid(11).setTask(task).build();
+
+        spyOn(task);
+        task.updateEffectiveIntent();
+        verify(task).setIntent(eq(activity0));
+    }
+
+    /**
+     * Test {@link Task#updateEffectiveIntent()} with activities set as relinquishTaskIdentity.
+     * This should make the task use the topmost activity when updating the intent.
+     */
+    @Test
+    public void testUpdateEffectiveIntent_relinquishingMultipleActivities() {
+        final ActivityRecord activity0 = new ActivityBuilder(mAtm)
+                .setActivityFlags(FLAG_RELINQUISH_TASK_IDENTITY).setCreateTask(true).build();
+        final Task task = activity0.getTask();
+        // Add an extra activity on top
+        final ActivityRecord activity1 = new ActivityBuilder(mAtm).setTask(task).build();
+        activity1.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
+
+        // Add an extra activity on top
+        final ActivityRecord activity2 = new ActivityBuilder(mAtm).setTask(task).build();
+
+        spyOn(task);
+        task.updateEffectiveIntent();
+        verify(task).setIntent(eq(activity2));
+    }
+
     @Test
     public void testSaveLaunchingStateWhenConfigurationChanged() {
         LaunchParamsPersister persister = mAtm.mTaskSupervisor.mLaunchParamsPersister;
@@ -1385,6 +1426,29 @@
         verify(task2).moveToFrontInner(anyString(), isNull());
     }
 
+    @Test
+    public void testResumeTask_doNotResumeTaskFragmentBehindTranslucent() {
+        final Task task = createTask(mDisplayContent);
+        final TaskFragment tfBehind = createTaskFragmentWithParentTask(
+                task, false /* createEmbeddedTask */);
+        final TaskFragment tfFront = createTaskFragmentWithParentTask(
+                task, false /* createEmbeddedTask */);
+        spyOn(tfFront);
+        doReturn(true).when(tfFront).isTranslucent(any());
+
+        // TaskFragment behind another translucent TaskFragment should not be resumed.
+        assertEquals(TASK_FRAGMENT_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
+                tfBehind.getVisibility(null /* starting */));
+        assertTrue(tfBehind.isFocusable());
+        assertFalse(tfBehind.canBeResumed(null /* starting */));
+
+        spyOn(tfBehind);
+        task.resumeTopActivityUncheckedLocked(null /* prev */, ActivityOptions.makeBasic(),
+                false /* deferPause */);
+
+        verify(tfBehind, never()).resumeTopActivity(any(), any(), anyBoolean());
+    }
+
     private Task getTestTask() {
         final Task task = new TaskBuilder(mSupervisor).setCreateActivity(true).build();
         return task.getBottomMostTask();
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 ec6cd92..ed3888c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -556,8 +556,15 @@
 
         // The redrawn window will be faded in when the transition finishes. And because this test
         // only use one non-activity window, the fade rotation controller should also be cleared.
-        statusBar.mWinAnimator.mDrawState = WindowStateAnimator.HAS_DRAWN;
+        statusBar.mWinAnimator.mDrawState = WindowStateAnimator.DRAW_PENDING;
+        final SurfaceControl.Transaction postDrawTransaction =
+                mock(SurfaceControl.Transaction.class);
+        final boolean layoutNeeded = statusBar.finishDrawing(postDrawTransaction);
+        assertFalse(layoutNeeded);
         player.finish();
+        // The controller should capture the draw transaction and merge it when preparing to run
+        // fade-in animation.
+        verify(mDisplayContent.getPendingTransaction()).merge(eq(postDrawTransaction));
         assertNull(mDisplayContent.getFadeRotationAnimationController());
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowLayoutTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowLayoutTests.java
index 117f2ff..338555e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowLayoutTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowLayoutTests.java
@@ -16,16 +16,32 @@
 
 package com.android.server.wm;
 
+import static android.view.InsetsState.ITYPE_BOTTOM_DISPLAY_CUTOUT;
+import static android.view.InsetsState.ITYPE_LEFT_DISPLAY_CUTOUT;
+import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
+import static android.view.InsetsState.ITYPE_RIGHT_DISPLAY_CUTOUT;
+import static android.view.InsetsState.ITYPE_STATUS_BAR;
+import static android.view.InsetsState.ITYPE_TOP_DISPLAY_CUTOUT;
 import static android.view.WindowLayout.UNSPECIFIED_LENGTH;
+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.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_NEVER;
+import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME;
 
 import static org.junit.Assert.assertEquals;
 
 import android.app.WindowConfiguration;
+import android.graphics.Insets;
 import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
+import android.view.DisplayCutout;
 import android.view.Gravity;
 import android.view.InsetsState;
 import android.view.InsetsVisibilities;
+import android.view.WindowInsets;
 import android.view.WindowLayout;
 import android.view.WindowManager;
 
@@ -35,7 +51,7 @@
 import org.junit.Test;
 
 /**
- * Tests for the {@link WindowLayout#computeWindowFrames}.
+ * Tests for the {@link WindowLayout#computeFrames}.
  *
  * Build/Install/Run:
  *  atest WmTests:WindowLayoutTests
@@ -47,6 +63,11 @@
     private static final int DISPLAY_HEIGHT = 1000;
     private static final int STATUS_BAR_HEIGHT = 10;
     private static final int NAVIGATION_BAR_HEIGHT = 15;
+    private static final int IME_HEIGHT = 400;
+    private static final int DISPLAY_CUTOUT_HEIGHT = 8;
+    private static final Rect DISPLAY_CUTOUT_BOUNDS_TOP =
+            new Rect(DISPLAY_WIDTH / 4, 0, DISPLAY_WIDTH * 3 / 4, DISPLAY_CUTOUT_HEIGHT);
+    private static final Insets WATERFALL_INSETS = Insets.of(6, 0, 12, 0);
 
     private final WindowLayout mWindowLayout = new WindowLayout();
     private final Rect mDisplayFrame = new Rect();
@@ -69,9 +90,9 @@
         mAttrs = new WindowManager.LayoutParams();
         mState = new InsetsState();
         mState.setDisplayFrame(new Rect(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT));
-        mState.getSource(InsetsState.ITYPE_STATUS_BAR).setFrame(
+        mState.getSource(ITYPE_STATUS_BAR).setFrame(
                 0, 0, DISPLAY_WIDTH, STATUS_BAR_HEIGHT);
-        mState.getSource(InsetsState.ITYPE_NAVIGATION_BAR).setFrame(
+        mState.getSource(ITYPE_NAVIGATION_BAR).setFrame(
                 0, DISPLAY_HEIGHT - NAVIGATION_BAR_HEIGHT, DISPLAY_WIDTH, DISPLAY_HEIGHT);
         mState.getDisplayCutoutSafe(mDisplayCutoutSafe);
         mWindowBounds = new Rect(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT);
@@ -83,34 +104,65 @@
         mCompatScale = 1f;
     }
 
-    @Test
-    public void testDefaultLayoutParams() {
-        computeWindowFrames();
+    private void computeFrames() {
+        mWindowLayout.computeFrames(mAttrs, mState, mDisplayCutoutSafe, mWindowBounds,
+                mWindowingMode, mRequestedWidth, mRequestedHeight, mRequestedVisibilities,
+                mAttachedWindowFrame, mCompatScale, mDisplayFrame, mParentFrame, mFrame);
+    }
 
-        assertRect(0, STATUS_BAR_HEIGHT, DISPLAY_WIDTH, DISPLAY_HEIGHT - NAVIGATION_BAR_HEIGHT,
-                mDisplayFrame);
-        assertRect(0, STATUS_BAR_HEIGHT, DISPLAY_WIDTH, DISPLAY_HEIGHT - NAVIGATION_BAR_HEIGHT,
-                mParentFrame);
-        assertRect(0, STATUS_BAR_HEIGHT, DISPLAY_WIDTH, DISPLAY_HEIGHT - NAVIGATION_BAR_HEIGHT,
-                mFrame);
+    private void addDisplayCutout() {
+        mState.setDisplayCutout(new DisplayCutout(
+                Insets.of(WATERFALL_INSETS.left, DISPLAY_CUTOUT_HEIGHT, WATERFALL_INSETS.right, 0),
+                new Rect(),
+                DISPLAY_CUTOUT_BOUNDS_TOP,
+                new Rect(),
+                new Rect(),
+                WATERFALL_INSETS));
+        mState.getDisplayCutoutSafe(mDisplayCutoutSafe);
+        mState.getSource(ITYPE_LEFT_DISPLAY_CUTOUT).setFrame(
+                0, 0, mDisplayCutoutSafe.left, DISPLAY_HEIGHT);
+        mState.getSource(ITYPE_TOP_DISPLAY_CUTOUT).setFrame(
+                0, 0, DISPLAY_WIDTH, mDisplayCutoutSafe.top);
+        mState.getSource(ITYPE_RIGHT_DISPLAY_CUTOUT).setFrame(
+                mDisplayCutoutSafe.right, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT);
+        mState.getSource(ITYPE_BOTTOM_DISPLAY_CUTOUT).setFrame(
+                0, mDisplayCutoutSafe.bottom, DISPLAY_WIDTH, DISPLAY_HEIGHT);
+    }
+
+    private static void assertInsetByTopBottom(int top, int bottom, Rect actual) {
+        assertInsetBy(0, top, 0, bottom, actual);
+    }
+
+    private static void assertInsetBy(int left, int top, int right, int bottom, Rect actual) {
+        assertRect(left, top, DISPLAY_WIDTH - right, DISPLAY_HEIGHT - bottom, actual);
+    }
+
+    private static void assertRect(int left, int top, int right, int bottom, Rect actual) {
+        assertEquals(new Rect(left, top, right, bottom), actual);
     }
 
     @Test
-    public void testUnmeasured() {
+    public void defaultParams() {
+        computeFrames();
+
+        assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mDisplayFrame);
+        assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mParentFrame);
+        assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mFrame);
+    }
+
+    @Test
+    public void unmeasured() {
         mRequestedWidth = UNSPECIFIED_LENGTH;
         mRequestedHeight = UNSPECIFIED_LENGTH;
-        computeWindowFrames();
+        computeFrames();
 
-        assertRect(0, STATUS_BAR_HEIGHT, DISPLAY_WIDTH, DISPLAY_HEIGHT - NAVIGATION_BAR_HEIGHT,
-                mDisplayFrame);
-        assertRect(0, STATUS_BAR_HEIGHT, DISPLAY_WIDTH, DISPLAY_HEIGHT - NAVIGATION_BAR_HEIGHT,
-                mParentFrame);
-        assertRect(0, STATUS_BAR_HEIGHT, DISPLAY_WIDTH, DISPLAY_HEIGHT - NAVIGATION_BAR_HEIGHT,
-                mFrame);
+        assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mDisplayFrame);
+        assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mParentFrame);
+        assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mFrame);
     }
 
     @Test
-    public void testUnmeasuredWithSizeSpecifiedInLayoutParams() {
+    public void unmeasuredWithSizeSpecifiedInLayoutParams() {
         final int width = DISPLAY_WIDTH / 2;
         final int height = DISPLAY_HEIGHT / 2;
         mRequestedWidth = UNSPECIFIED_LENGTH;
@@ -118,41 +170,218 @@
         mAttrs.width = width;
         mAttrs.height = height;
         mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
-        computeWindowFrames();
+        computeFrames();
 
-        assertRect(0, STATUS_BAR_HEIGHT, DISPLAY_WIDTH, DISPLAY_HEIGHT - NAVIGATION_BAR_HEIGHT,
-                mDisplayFrame);
-        assertRect(0, STATUS_BAR_HEIGHT, DISPLAY_WIDTH, DISPLAY_HEIGHT - NAVIGATION_BAR_HEIGHT,
-                mParentFrame);
-        assertRect(0, STATUS_BAR_HEIGHT, width, STATUS_BAR_HEIGHT + height,
-                mFrame);
+        assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mDisplayFrame);
+        assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mParentFrame);
+        assertRect(0, STATUS_BAR_HEIGHT, width, STATUS_BAR_HEIGHT + height, mFrame);
     }
 
     @Test
-    public void testNonFullscreenWindowBounds() {
+    public void nonFullscreenWindowBounds() {
         final int top = Math.max(DISPLAY_HEIGHT / 2, STATUS_BAR_HEIGHT);
         mWindowBounds.set(0, top, DISPLAY_WIDTH, DISPLAY_HEIGHT);
         mRequestedWidth = UNSPECIFIED_LENGTH;
         mRequestedHeight = UNSPECIFIED_LENGTH;
-        computeWindowFrames();
+        computeFrames();
 
-        assertRect(0, top, DISPLAY_WIDTH, DISPLAY_HEIGHT - NAVIGATION_BAR_HEIGHT,
+        assertRect(0, top, DISPLAY_WIDTH, DISPLAY_HEIGHT - NAVIGATION_BAR_HEIGHT, mDisplayFrame);
+        assertRect(0, top, DISPLAY_WIDTH, DISPLAY_HEIGHT - NAVIGATION_BAR_HEIGHT, mParentFrame);
+        assertRect(0, top, DISPLAY_WIDTH, DISPLAY_HEIGHT - NAVIGATION_BAR_HEIGHT, mFrame);
+    }
+
+    @Test
+    public void fitStatusBars() {
+        mAttrs.setFitInsetsTypes(WindowInsets.Type.statusBars());
+        computeFrames();
+
+        assertInsetByTopBottom(STATUS_BAR_HEIGHT, 0, mDisplayFrame);
+        assertInsetByTopBottom(STATUS_BAR_HEIGHT, 0, mParentFrame);
+        assertInsetByTopBottom(STATUS_BAR_HEIGHT, 0, mFrame);
+    }
+
+    @Test
+    public void fitNavigationBars() {
+        mAttrs.setFitInsetsTypes(WindowInsets.Type.navigationBars());
+        computeFrames();
+
+        assertInsetByTopBottom(0, NAVIGATION_BAR_HEIGHT, mDisplayFrame);
+        assertInsetByTopBottom(0, NAVIGATION_BAR_HEIGHT, mParentFrame);
+        assertInsetByTopBottom(0, NAVIGATION_BAR_HEIGHT, mFrame);
+    }
+
+    @Test
+    public void fitZeroTypes() {
+        mAttrs.setFitInsetsTypes(0);
+        computeFrames();
+
+        assertInsetByTopBottom(0, 0, mDisplayFrame);
+        assertInsetByTopBottom(0, 0, mParentFrame);
+        assertInsetByTopBottom(0, 0, mFrame);
+    }
+
+    @Test
+    public void fitAllSides() {
+        mAttrs.setFitInsetsSides(WindowInsets.Side.all());
+        computeFrames();
+
+        assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mDisplayFrame);
+        assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mParentFrame);
+        assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mFrame);
+    }
+
+    @Test
+    public void fitTopOnly() {
+        mAttrs.setFitInsetsSides(WindowInsets.Side.TOP);
+        computeFrames();
+
+        assertInsetByTopBottom(STATUS_BAR_HEIGHT, 0, mDisplayFrame);
+        assertInsetByTopBottom(STATUS_BAR_HEIGHT, 0, mParentFrame);
+        assertInsetByTopBottom(STATUS_BAR_HEIGHT, 0, mFrame);
+    }
+
+    @Test
+    public void fitZeroSides() {
+        mAttrs.setFitInsetsSides(0);
+        computeFrames();
+
+        assertInsetByTopBottom(0, 0, mDisplayFrame);
+        assertInsetByTopBottom(0, 0, mParentFrame);
+        assertInsetByTopBottom(0, 0, mFrame);
+    }
+
+    @Test
+    public void fitInvisibleInsets() {
+        mState.getSource(ITYPE_STATUS_BAR).setVisible(false);
+        mState.getSource(ITYPE_NAVIGATION_BAR).setVisible(false);
+        computeFrames();
+
+        assertInsetByTopBottom(0, 0, mDisplayFrame);
+        assertInsetByTopBottom(0, 0, mParentFrame);
+        assertInsetByTopBottom(0, 0, mFrame);
+    }
+
+    @Test
+    public void fitInvisibleInsetsIgnoringVisibility() {
+        mState.getSource(ITYPE_STATUS_BAR).setVisible(false);
+        mState.getSource(ITYPE_NAVIGATION_BAR).setVisible(false);
+        mAttrs.setFitInsetsIgnoringVisibility(true);
+        computeFrames();
+
+        assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mDisplayFrame);
+        assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mParentFrame);
+        assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mFrame);
+    }
+
+    @Test
+    public void insetParentFrameByIme() {
+        mState.getSource(InsetsState.ITYPE_IME).setVisible(true);
+        mState.getSource(InsetsState.ITYPE_IME).setFrame(
+                0, DISPLAY_HEIGHT - IME_HEIGHT, DISPLAY_WIDTH, DISPLAY_HEIGHT);
+        mAttrs.privateFlags |= PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME;
+        computeFrames();
+
+        assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mDisplayFrame);
+        assertInsetByTopBottom(STATUS_BAR_HEIGHT, IME_HEIGHT, mParentFrame);
+        assertInsetByTopBottom(STATUS_BAR_HEIGHT, IME_HEIGHT, mFrame);
+    }
+
+    @Test
+    public void fitDisplayCutout() {
+        addDisplayCutout();
+        mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+        mAttrs.setFitInsetsTypes(WindowInsets.Type.displayCutout());
+        computeFrames();
+
+        assertInsetBy(WATERFALL_INSETS.left, DISPLAY_CUTOUT_HEIGHT, WATERFALL_INSETS.right, 0,
                 mDisplayFrame);
-        assertRect(0, top, DISPLAY_WIDTH, DISPLAY_HEIGHT - NAVIGATION_BAR_HEIGHT,
+        assertInsetBy(WATERFALL_INSETS.left, DISPLAY_CUTOUT_HEIGHT, WATERFALL_INSETS.right, 0,
                 mParentFrame);
-        assertRect(0, top, DISPLAY_WIDTH, DISPLAY_HEIGHT - NAVIGATION_BAR_HEIGHT,
+        assertInsetBy(WATERFALL_INSETS.left, DISPLAY_CUTOUT_HEIGHT, WATERFALL_INSETS.right, 0,
                 mFrame);
     }
 
-    // TODO(b/161810301): Move tests here from DisplayPolicyLayoutTests and add more tests.
+    @Test
+    public void layoutInDisplayCutoutModeDefault() {
+        addDisplayCutout();
+        mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT;
+        mAttrs.setFitInsetsTypes(0);
+        computeFrames();
 
-    private void computeWindowFrames() {
-        mWindowLayout.computeWindowFrames(mAttrs, mState, mDisplayCutoutSafe, mWindowBounds,
-                mWindowingMode, mRequestedWidth, mRequestedHeight, mRequestedVisibilities,
-                mAttachedWindowFrame, mCompatScale, mDisplayFrame, mParentFrame, mFrame);
+        assertInsetBy(WATERFALL_INSETS.left, STATUS_BAR_HEIGHT, WATERFALL_INSETS.right, 0,
+                mDisplayFrame);
+        assertInsetBy(WATERFALL_INSETS.left, STATUS_BAR_HEIGHT, WATERFALL_INSETS.right, 0,
+                mParentFrame);
+        assertInsetBy(WATERFALL_INSETS.left, STATUS_BAR_HEIGHT, WATERFALL_INSETS.right, 0,
+                mFrame);
     }
 
-    private void assertRect(int left, int top, int right, int bottom, Rect actual) {
-        assertEquals(new Rect(left, top, right, bottom), actual);
+    @Test
+    public void layoutInDisplayCutoutModeDefaultWithLayoutInScreenAndLayoutInsetDecor() {
+        addDisplayCutout();
+        mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT;
+        mAttrs.flags = FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR;
+        mAttrs.setFitInsetsTypes(0);
+        computeFrames();
+
+        assertInsetBy(WATERFALL_INSETS.left, 0, WATERFALL_INSETS.right, 0, mDisplayFrame);
+        assertInsetBy(WATERFALL_INSETS.left, 0, WATERFALL_INSETS.right, 0, mParentFrame);
+        assertInsetBy(WATERFALL_INSETS.left, 0, WATERFALL_INSETS.right, 0, mFrame);
+    }
+
+    @Test
+    public void layoutInDisplayCutoutModeDefaultWithInvisibleSystemBars() {
+        addDisplayCutout();
+        mState.getSource(ITYPE_STATUS_BAR).setVisible(false);
+        mState.getSource(ITYPE_NAVIGATION_BAR).setVisible(false);
+        mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT;
+        mAttrs.setFitInsetsTypes(0);
+        computeFrames();
+
+        assertInsetBy(WATERFALL_INSETS.left, STATUS_BAR_HEIGHT, WATERFALL_INSETS.right, 0,
+                mDisplayFrame);
+        assertInsetBy(WATERFALL_INSETS.left, STATUS_BAR_HEIGHT, WATERFALL_INSETS.right, 0,
+                mParentFrame);
+        assertInsetBy(WATERFALL_INSETS.left, STATUS_BAR_HEIGHT, WATERFALL_INSETS.right, 0,
+                mFrame);
+    }
+
+    @Test
+    public void layoutInDisplayCutoutModeShortEdges() {
+        addDisplayCutout();
+        mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
+        mAttrs.setFitInsetsTypes(0);
+        computeFrames();
+
+        assertInsetBy(WATERFALL_INSETS.left, 0, WATERFALL_INSETS.right, 0, mDisplayFrame);
+        assertInsetBy(WATERFALL_INSETS.left, 0, WATERFALL_INSETS.right, 0, mParentFrame);
+        assertInsetBy(WATERFALL_INSETS.left, 0, WATERFALL_INSETS.right, 0, mFrame);
+    }
+
+    @Test
+    public void layoutInDisplayCutoutModeNever() {
+        addDisplayCutout();
+        mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;
+        mAttrs.setFitInsetsTypes(0);
+        computeFrames();
+
+        assertInsetBy(WATERFALL_INSETS.left, STATUS_BAR_HEIGHT, WATERFALL_INSETS.right, 0,
+                mDisplayFrame);
+        assertInsetBy(WATERFALL_INSETS.left, STATUS_BAR_HEIGHT, WATERFALL_INSETS.right, 0,
+                mParentFrame);
+        assertInsetBy(WATERFALL_INSETS.left, STATUS_BAR_HEIGHT, WATERFALL_INSETS.right, 0,
+                mFrame);
+    }
+
+    @Test
+    public void layoutInDisplayCutoutModeAlways() {
+        addDisplayCutout();
+        mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+        mAttrs.setFitInsetsTypes(0);
+        computeFrames();
+
+        assertInsetByTopBottom(0, 0, mDisplayFrame);
+        assertInsetByTopBottom(0, 0, mParentFrame);
+        assertInsetByTopBottom(0, 0, mFrame);
     }
 }
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 ca2b4ae..ec8ec2b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -252,6 +252,11 @@
         assertFalse(appWindow.canBeImeTarget());
         appWindow.mActivityRecord.setWindowingMode(initialMode);
 
+        // Verify that app window can still be IME target as long as it is visible (even if
+        // it is going to become invisible).
+        appWindow.mActivityRecord.mVisibleRequested = false;
+        assertTrue(appWindow.canBeImeTarget());
+
         // Make windows invisible
         appWindow.hide(false /* doAnimation */, false /* requestAnim */);
         imeWindow.hide(false /* doAnimation */, false /* requestAnim */);
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 a985de5..34038c5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -132,6 +132,9 @@
     // Default base activity name
     private static final String DEFAULT_COMPONENT_CLASS_NAME = ".BarActivity";
 
+    // An id appended to the end of the component name to make it unique
+    static int sCurrentActivityId = 0;
+
     ActivityTaskManagerService mAtm;
     RootWindowContainer mRootWindowContainer;
     ActivityTaskSupervisor mSupervisor;
@@ -895,13 +898,16 @@
         doReturn(100).when(hardwareBuffer).getHeight();
     }
 
+    private static ComponentName getUniqueComponentName() {
+        return ComponentName.createRelative(DEFAULT_COMPONENT_PACKAGE_NAME,
+                DEFAULT_COMPONENT_CLASS_NAME + sCurrentActivityId++);
+    }
+
     /**
      * Builder for creating new activities.
      */
     protected static class ActivityBuilder {
         static final int DEFAULT_FAKE_UID = 12345;
-        // An id appended to the end of the component name to make it unique
-        private static int sCurrentActivityId = 0;
 
         private final ActivityTaskManagerService mService;
 
@@ -1077,9 +1083,7 @@
 
         ActivityRecord buildInner() {
             if (mComponent == null) {
-                final int id = sCurrentActivityId++;
-                mComponent = ComponentName.createRelative(DEFAULT_COMPONENT_PACKAGE_NAME,
-                        DEFAULT_COMPONENT_CLASS_NAME + id);
+                mComponent = getUniqueComponentName();
             }
 
             Intent intent = new Intent();
@@ -1388,8 +1392,7 @@
             if (mIntent == null) {
                 mIntent = new Intent();
                 if (mComponent == null) {
-                    mComponent = ComponentName.createRelative(DEFAULT_COMPONENT_PACKAGE_NAME,
-                            DEFAULT_COMPONENT_CLASS_NAME);
+                    mComponent = getUniqueComponentName();
                 }
                 mIntent.setComponent(mComponent);
                 mIntent.setFlags(mFlags);
@@ -1422,10 +1425,11 @@
             doNothing().when(rootTask).startActivityLocked(
                     any(), any(), anyBoolean(), anyBoolean(), any(), any());
 
-            // Create child task with activity.
+            // Create child activity.
             if (mCreateActivity) {
                 new ActivityBuilder(mSupervisor.mService)
                         .setTask(task)
+                        .setComponent(mComponent)
                         .build();
                 if (mOnTop) {
                     // We move the task to front again in order to regain focus after activity
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 4220fd7..2fb67d7 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -175,10 +175,7 @@
     // Delay for debouncing USB disconnects.
     // We often get rapid connect/disconnect events when enabling USB functions,
     // which need debouncing.
-    private static final int DEVICE_STATE_UPDATE_DELAY = 3000;
-
-    // Delay for debouncing USB disconnects on Type-C ports in host mode
-    private static final int HOST_STATE_UPDATE_DELAY = 1000;
+    private static final int UPDATE_DELAY = 1000;
 
     // Timeout for entering USB request mode.
     // Request is cancelled if host does not configure device within 10 seconds.
@@ -648,7 +645,7 @@
             msg.arg1 = connected;
             msg.arg2 = configured;
             // debounce disconnects to avoid problems bringing up USB tethering
-            sendMessageDelayed(msg, (connected == 0) ? DEVICE_STATE_UPDATE_DELAY : 0);
+            sendMessageDelayed(msg, (connected == 0) ? UPDATE_DELAY : 0);
         }
 
         public void updateHostState(UsbPort port, UsbPortStatus status) {
@@ -663,7 +660,7 @@
             removeMessages(MSG_UPDATE_PORT_STATE);
             Message msg = obtainMessage(MSG_UPDATE_PORT_STATE, args);
             // debounce rapid transitions of connect/disconnect on type-c ports
-            sendMessageDelayed(msg, HOST_STATE_UPDATE_DELAY);
+            sendMessageDelayed(msg, UPDATE_DELAY);
         }
 
         private void setAdbEnabled(boolean enable) {
diff --git a/telecomm/java/android/telecom/CallScreeningService.java b/telecomm/java/android/telecom/CallScreeningService.java
index 7861b11..37b4e65 100644
--- a/telecomm/java/android/telecom/CallScreeningService.java
+++ b/telecomm/java/android/telecom/CallScreeningService.java
@@ -632,8 +632,9 @@
      * post-dial digits are passed.
      * <p>
      * Calls with a {@link Call.Details#getHandlePresentation()} of
-     * {@link TelecomManager#PRESENTATION_RESTRICTED}, {@link TelecomManager#PRESENTATION_UNKNOWN}
-     * or {@link TelecomManager#PRESENTATION_PAYPHONE} presentation are not provided to the
+     * {@link TelecomManager#PRESENTATION_RESTRICTED}, {@link TelecomManager#PRESENTATION_UNKNOWN},
+     * {@link TelecomManager#PRESENTATION_UNAVAILABLE} or
+     * {@link TelecomManager#PRESENTATION_PAYPHONE} presentation are not provided to the
      * {@link CallScreeningService}.
      *
      * @param callDetails Information about a new call, see {@link Call.Details}.
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 0dc899e..6279bf8 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -990,6 +990,11 @@
      */
     public static final int PRESENTATION_PAYPHONE = 4;
 
+    /**
+     * Indicates that the address or number of a call is unavailable.
+     */
+    public static final int PRESENTATION_UNAVAILABLE = 5;
+
 
     /*
      * Values for the adb property "persist.radio.videocall.audio.output"
@@ -1006,7 +1011,7 @@
     @IntDef(
             prefix = { "PRESENTATION_" },
             value = {PRESENTATION_ALLOWED, PRESENTATION_RESTRICTED, PRESENTATION_UNKNOWN,
-            PRESENTATION_PAYPHONE})
+            PRESENTATION_PAYPHONE, PRESENTATION_UNAVAILABLE})
     public @interface Presentation {}
 
 
diff --git a/telephony/common/com/google/android/mms/util/SqliteWrapper.java b/telephony/common/com/google/android/mms/util/SqliteWrapper.java
index e2d62f8..6d9b3210 100644
--- a/telephony/common/com/google/android/mms/util/SqliteWrapper.java
+++ b/telephony/common/com/google/android/mms/util/SqliteWrapper.java
@@ -17,7 +17,6 @@
 
 package com.google.android.mms.util;
 
-import android.app.ActivityManager;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ContentResolver;
 import android.content.ContentValues;
@@ -25,49 +24,15 @@
 import android.database.Cursor;
 import android.database.sqlite.SQLiteException;
 import android.net.Uri;
-import android.os.Build;
 import android.util.Log;
-import android.widget.Toast;
 
 public final class SqliteWrapper {
     private static final String TAG = "SqliteWrapper";
-    private static final String SQLITE_EXCEPTION_DETAIL_MESSAGE
-                = "unable to open database file";
 
     private SqliteWrapper() {
         // Forbidden being instantiated.
     }
 
-    // FIXME: It looks like outInfo.lowMemory does not work well as we expected.
-    // after run command: adb shell fillup -p 100, outInfo.lowMemory is still false.
-    private static boolean isLowMemory(Context context) {
-        if (null == context) {
-            return false;
-        }
-
-        ActivityManager am = (ActivityManager)
-                        context.getSystemService(Context.ACTIVITY_SERVICE);
-        ActivityManager.MemoryInfo outInfo = new ActivityManager.MemoryInfo();
-        am.getMemoryInfo(outInfo);
-
-        return outInfo.lowMemory;
-    }
-
-    // FIXME: need to optimize this method.
-    private static boolean isLowMemory(SQLiteException e) {
-        return e.getMessage().equals(SQLITE_EXCEPTION_DETAIL_MESSAGE);
-    }
-
-    @UnsupportedAppUsage
-    public static void checkSQLiteException(Context context, SQLiteException e) {
-        if (isLowMemory(e)) {
-            Toast.makeText(context, com.android.internal.R.string.low_memory,
-                    Toast.LENGTH_SHORT).show();
-        } else {
-            throw e;
-        }
-    }
-
     @UnsupportedAppUsage
     public static Cursor query(Context context, ContentResolver resolver, Uri uri,
             String[] projection, String selection, String[] selectionArgs, String sortOrder) {
@@ -75,21 +40,10 @@
             return resolver.query(uri, projection, selection, selectionArgs, sortOrder);
         } catch (SQLiteException e) {
             Log.e(TAG, "Catch a SQLiteException when query: ", e);
-            checkSQLiteException(context, e);
             return null;
         }
     }
 
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    public static boolean requery(Context context, Cursor cursor) {
-        try {
-            return cursor.requery();
-        } catch (SQLiteException e) {
-            Log.e(TAG, "Catch a SQLiteException when requery: ", e);
-            checkSQLiteException(context, e);
-            return false;
-        }
-    }
     @UnsupportedAppUsage
     public static int update(Context context, ContentResolver resolver, Uri uri,
             ContentValues values, String where, String[] selectionArgs) {
@@ -97,7 +51,6 @@
             return resolver.update(uri, values, where, selectionArgs);
         } catch (SQLiteException e) {
             Log.e(TAG, "Catch a SQLiteException when update: ", e);
-            checkSQLiteException(context, e);
             return -1;
         }
     }
@@ -109,7 +62,6 @@
             return resolver.delete(uri, where, selectionArgs);
         } catch (SQLiteException e) {
             Log.e(TAG, "Catch a SQLiteException when delete: ", e);
-            checkSQLiteException(context, e);
             return -1;
         }
     }
@@ -121,7 +73,6 @@
             return resolver.insert(uri, values);
         } catch (SQLiteException e) {
             Log.e(TAG, "Catch a SQLiteException when insert: ", e);
-            checkSQLiteException(context, e);
             return null;
         }
     }
diff --git a/telephony/java/android/service/euicc/EuiccService.java b/telephony/java/android/service/euicc/EuiccService.java
index fabe612..184e154 100644
--- a/telephony/java/android/service/euicc/EuiccService.java
+++ b/telephony/java/android/service/euicc/EuiccService.java
@@ -23,6 +23,7 @@
 import android.annotation.Nullable;
 import android.annotation.SdkConstant;
 import android.annotation.SystemApi;
+import android.app.PendingIntent;
 import android.app.Service;
 import android.content.Intent;
 import android.os.Bundle;
@@ -261,6 +262,14 @@
     public static final String EXTRA_RESOLUTION_PORT_INDEX =
             "android.service.euicc.extra.RESOLUTION_PORT_INDEX";
 
+    /**
+     * Intent extra set for resolution requests containing a bool indicating whether to use the
+     * given port index. For example, if {@link #switchToSubscription(int, PendingIntent)} is
+     * called, then no portIndex has been provided by the caller, and this extra will be false.
+     */
+    public static final String EXTRA_RESOLUTION_USE_PORT_INDEX =
+            "android.service.euicc.extra.RESOLUTION_USE_PORT_INDEX";
+
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(prefix = { "RESULT_" }, value = {
@@ -852,14 +861,19 @@
         }
         @Override
         public void switchToSubscription(int slotId, int portIndex, String iccid,
-                boolean forceDeactivateSim, ISwitchToSubscriptionCallback callback) {
+                boolean forceDeactivateSim, ISwitchToSubscriptionCallback callback,
+                boolean usePortIndex) {
             mExecutor.execute(new Runnable() {
                 @Override
                 public void run() {
-                    // TODO(b/207392528: use portIndex API once implemented)
-                    int result =
-                            EuiccService.this.onSwitchToSubscription(
-                                    slotId, iccid, forceDeactivateSim);
+                    int result = 0;
+                    if (usePortIndex) {
+                        result = EuiccService.this.onSwitchToSubscriptionWithPort(
+                                slotId, portIndex, iccid, forceDeactivateSim);
+                    } else {
+                        result = EuiccService.this.onSwitchToSubscription(
+                                slotId, iccid, forceDeactivateSim);
+                    }
                     try {
                         callback.onComplete(result);
                     } catch (RemoteException e) {
diff --git a/telephony/java/android/service/euicc/IEuiccService.aidl b/telephony/java/android/service/euicc/IEuiccService.aidl
index aa30c9e..030e11a 100644
--- a/telephony/java/android/service/euicc/IEuiccService.aidl
+++ b/telephony/java/android/service/euicc/IEuiccService.aidl
@@ -49,7 +49,7 @@
     void getEuiccInfo(int slotId, in IGetEuiccInfoCallback callback);
     void deleteSubscription(int slotId, String iccid, in IDeleteSubscriptionCallback callback);
     void switchToSubscription(int slotId, int portIndex, String iccid, boolean forceDeactivateSim,
-            in ISwitchToSubscriptionCallback callback);
+            in ISwitchToSubscriptionCallback callback, boolean useLegacyApi);
     void updateSubscriptionNickname(int slotId, String iccid, String nickname,
             in IUpdateSubscriptionNicknameCallback callback);
     void eraseSubscriptions(int slotId, in IEraseSubscriptionsCallback callback);
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 3f6d913..8e55f75 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -798,6 +798,14 @@
             "carrier_cross_sim_ims_available_bool";
 
     /**
+     * Flag specifying whether cross sim calling on opportunistic data is supported for carrier.
+     * When {@code false} the carrier does not support cross sim calling on opportunistic data.
+     * When {@code true} the carrier does support cross sim calling on opportunistic data.
+     */
+    public static final String KEY_ENABLE_CROSS_SIM_CALLING_ON_OPPORTUNISTIC_DATA_BOOL =
+            "enable_cross_sim_calling_on_opportunistic_data_bool";
+
+    /**
      * Specifies a map from dialstrings to replacements for roaming network service numbers which
      * cannot be replaced on the carrier side.
      * <p>
@@ -2265,6 +2273,7 @@
      * android.provider.BlockedNumberContract.SystemContract#ENHANCED_SETTING_KEY_BLOCK_PRIVATE
      * android.provider.BlockedNumberContract.SystemContract#ENHANCED_SETTING_KEY_BLOCK_PAYPHONE
      * android.provider.BlockedNumberContract.SystemContract#ENHANCED_SETTING_KEY_BLOCK_UNKNOWN
+     * android.provider.BlockedNumberContract.SystemContract#ENHANCED_SETTING_KEY_BLOCK_UNAVAILABLE
      *
      * <p>
      * 1. For Single SIM(SS) device, it can be customized in both carrier_config_mccmnc.xml
@@ -4181,6 +4190,56 @@
             "gba_ua_tls_cipher_suite_int";
 
     /**
+     * The data stall recovery timers array in milliseconds, each element is the delay before
+     * performining next recovery action.
+     *
+     * The default value of timers array are: [180000ms, 180000ms, 180000ms] (3 minutes)
+     * Array[0]: It's the timer between RECOVERY_ACTION GET_DATA_CALL_LIST and CLEANUP, if data
+     * stall symptom still occurred, it will perform next recovery action after 180000ms.
+     * Array[1]: It's the timer between RECOVERY_ACTION CLEANUP and RADIO_RESTART, if data stall
+     * symptom still occurred, it will perform next recovery action after 180000ms.
+     * Array[2]: It's the timer between RECOVERY_ACTION RADIO_RESTART and RESET_MODEM, if data stall
+     * symptom still occurred, it will perform next recovery action after 180000ms.
+     *
+     * See the {@code RECOVERY_ACTION_*} constants in
+     * {@link com.android.internal.telephony.data.DataStallRecoveryManager}
+     * @hide
+     */
+    public static final String KEY_DATA_STALL_RECOVERY_TIMERS_LONG_ARRAY =
+            "data_stall_recovery_timers_long_array";
+
+    /**
+     * The data stall recovery action boolean array, we use this array to determine if the
+     * data stall recovery action needs to be skipped.
+     *
+     * For example, if the carrier use the same APN for both of IA and default type,
+     * the data call will not disconnect in modem side (so the RECOVERY_ACTION_CLEANUP
+     * did not effect). In this case, we can config the boolean variable of action
+     * RECOVERY_ACTION_CLEANUP to true, then it can be ignored to speed up the recovery
+     * action procedure.
+     *
+     * The default value of boolean array are: [false, false, false, false]
+     * Array[0]: When performing the recovery action, we can use this boolean value to determine
+     * if we need to perform RECOVERY_ACTION_GET_DATA_CALL_LIST.
+     * Array[1]: If data stall symptom still occurred, we can use this boolean value to determine
+     * if we need to perform RECOVERY_ACTION_CLEANUP. For example, if the carrier use the same APN
+     * for both of IA and default type, the data call will not disconnect in modem side
+     * (so the RECOVERY_ACTION_CLEANUP did not effect). In this case, we can config the boolean
+     * variable of action RECOVERY_ACTION_CLEANUP to true, then it can be ignored to speed up the
+     * recovery action procedure.
+     * Array[2]: If data stall symptom still occurred, we can use this boolean value to determine
+     * if we need to perform RECOVERY_ACTION_RADIO_RESTART.
+     * Array[3]: If data stall symptom still occurred, we can use this boolean value to determine
+     * if we need to perform RECOVERY_ACTION_MODEM_RESET.
+     *
+     * See the {@code RECOVERY_ACTION_*} constants in
+     * {@link com.android.internal.telephony.data.DataStallRecoveryManager}
+     * @hide
+     */
+    public static final String KEY_DATA_STALL_RECOVERY_SHOULD_SKIP_BOOL_ARRAY =
+            "data_stall_recovery_should_skip_bool_array";
+
+    /**
      * Configs used by ImsServiceEntitlement.
      */
     public static final class ImsServiceEntitlement {
@@ -5230,7 +5289,7 @@
             "telephony_network_capability_priorities_string_array";
 
     /**
-     * Defines the rules for data retry.
+     * Defines the rules for data setup retry.
      *
      * The syntax of the retry rule:
      * 1. Retry based on {@link NetworkCapabilities}. Note that only APN-type network capabilities
@@ -5262,8 +5321,34 @@
      * // TODO: remove KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS
      * @hide
      */
-    public static final String KEY_TELEPHONY_DATA_RETRY_RULES_STRING_ARRAY =
-            "telephony_data_retry_rules_string_array";
+    public static final String KEY_TELEPHONY_DATA_SETUP_RETRY_RULES_STRING_ARRAY =
+            "telephony_data_setup_retry_rules_string_array";
+
+    /**
+     * Defines the rules for data handover retry.
+     *
+     * The syntax of the retry rule:
+     * 1. Retry when handover fails.
+     * "retry_interval=[n1|n2|n3|...], [maximum_retries=n]"
+     *
+     * For example,
+     * "retry_interval=1000|3000|5000, maximum_retries=10" means handover retry will happen in 1s,
+     * 3s, 5s, 5s, 5s....up to 10 times.
+     *
+     * 2. Retry when handover fails with certain fail causes.
+     * "retry_interval=[n1|n2|n3|...], fail_causes=[cause1|cause2|cause3|...], [maximum_retries=n]
+     *
+     * For example,
+     * "retry_interval=1000, maximum_retries=3, fail_causes=5" means handover retry every 1 second
+     * for up to 3 times when handover fails with the cause 5.
+     *
+     * "maximum_retries=0, fail_causes=6|10|67" means handover retry should not happen for those
+     * causes.
+     *
+     * @hide
+     */
+    public static final String KEY_TELEPHONY_DATA_HANDOVER_RETRY_RULES_STRING_ARRAY =
+            "telephony_data_handover_retry_rules_string_array";
 
     /**
      * The patterns of missed incoming call sms. This is the regular expression used for
@@ -5511,6 +5596,7 @@
         sDefaults.putBoolean(KEY_VILTE_DATA_IS_METERED_BOOL, true);
         sDefaults.putBoolean(KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL, false);
         sDefaults.putBoolean(KEY_CARRIER_CROSS_SIM_IMS_AVAILABLE_BOOL, false);
+        sDefaults.putBoolean(KEY_ENABLE_CROSS_SIM_CALLING_ON_OPPORTUNISTIC_DATA_BOOL, false);
         sDefaults.putBoolean(KEY_CARRIER_WFC_SUPPORTS_WIFI_ONLY_BOOL, false);
         sDefaults.putBoolean(KEY_CARRIER_DEFAULT_WFC_IMS_ENABLED_BOOL, false);
         sDefaults.putBoolean(KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_ENABLED_BOOL, false);
@@ -5624,7 +5710,7 @@
                 "others:max_retries=3, 5000, 5000, 5000"});
         sDefaults.putLong(KEY_CARRIER_DATA_CALL_APN_DELAY_DEFAULT_LONG, 20000);
         sDefaults.putLong(KEY_CARRIER_DATA_CALL_APN_DELAY_FASTER_LONG, 3000);
-        sDefaults.putLong(KEY_CARRIER_DATA_CALL_APN_RETRY_AFTER_DISCONNECT_LONG, 10000);
+        sDefaults.putLong(KEY_CARRIER_DATA_CALL_APN_RETRY_AFTER_DISCONNECT_LONG, 3000);
         sDefaults.putInt(KEY_CARRIER_DATA_CALL_RETRY_NETWORK_REQUESTED_MAX_COUNT_INT, 3);
         sDefaults.putString(KEY_CARRIER_ERI_FILE_NAME_STRING, "eri.xml");
         sDefaults.putInt(KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT, 7200);
@@ -6108,7 +6194,7 @@
                         "ims:40", "dun:30", "enterprise:20", "internet:20"
                 });
         sDefaults.putStringArray(
-                KEY_TELEPHONY_DATA_RETRY_RULES_STRING_ARRAY, new String[] {
+                KEY_TELEPHONY_DATA_SETUP_RETRY_RULES_STRING_ARRAY, new String[] {
                         "capabilities=eims, retry_interval=1000, maximum_retries=20",
                         "fail_causes=8|27|28|29|30|32|33|35|50|51|111|-5|-6|65537|65538|-3|2253|"
                                 + "2254, maximum_retries=0", // No retry for those causes
@@ -6117,6 +6203,10 @@
                                 + "5000|10000|15000|20000|40000|60000|120000|240000|"
                                 + "600000|1200000|1800000, maximum_retries=20"
                 });
+        sDefaults.putStringArray(
+                KEY_TELEPHONY_DATA_HANDOVER_RETRY_RULES_STRING_ARRAY, new String[] {
+                        "retry_interval=1000|2000|4000|8000|16000, maximum_retries=5"
+                });
         sDefaults.putStringArray(KEY_MISSED_INCOMING_CALL_SMS_PATTERN_STRING_ARRAY, new String[0]);
         sDefaults.putBoolean(KEY_DISABLE_DUN_APN_WHILE_ROAMING_WITH_PRESET_APN_BOOL, false);
         sDefaults.putString(KEY_DEFAULT_PREFERRED_APN_NAME_STRING, "");
@@ -6142,6 +6232,11 @@
                         + "target=GERAN|UTRAN|EUTRAN|NGRAN|IWLAN, type=allowed"});
         sDefaults.putInt(KEY_CELLULAR_USAGE_SETTING_INT,
                 SubscriptionManager.USAGE_SETTING_UNKNOWN);
+        // Default data stall recovery configurations.
+        sDefaults.putLongArray(KEY_DATA_STALL_RECOVERY_TIMERS_LONG_ARRAY,
+                new long[] {180000, 180000, 180000});
+        sDefaults.putBooleanArray(KEY_DATA_STALL_RECOVERY_SHOULD_SKIP_BOOL_ARRAY,
+                new boolean[] {false, false, false, false});
     }
 
     /**
diff --git a/telephony/java/android/telephony/CellSignalStrengthLte.java b/telephony/java/android/telephony/CellSignalStrengthLte.java
index e8633dd..947dc01 100644
--- a/telephony/java/android/telephony/CellSignalStrengthLte.java
+++ b/telephony/java/android/telephony/CellSignalStrengthLte.java
@@ -600,7 +600,7 @@
 
     /** @hide */
     public static int convertRssnrUnitFromTenDbToDB(int rssnr) {
-        return rssnr / 10;
+        return (int) Math.floor((float) rssnr / 10);
     }
 
     /** @hide */
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index d835ea4..f5505e6 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -6145,6 +6145,7 @@
             DATA_CONNECTED,
             DATA_SUSPENDED,
             DATA_DISCONNECTING,
+            DATA_HANDOVER_IN_PROGRESS,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface DataState{}
@@ -6169,6 +6170,12 @@
     public static final int DATA_DISCONNECTING = 4;
 
     /**
+     * Data connection state: Handover in progress. The connection is being transited from cellular
+     * network to IWLAN, or from IWLAN to cellular network.
+     */
+    public static final int DATA_HANDOVER_IN_PROGRESS = 5;
+
+    /**
      * Used for checking if the SDK version for {@link TelephonyManager#getDataState} is above Q.
      */
     @ChangeId
@@ -6184,6 +6191,7 @@
      * @see #DATA_CONNECTED
      * @see #DATA_SUSPENDED
      * @see #DATA_DISCONNECTING
+     * @see #DATA_HANDOVER_IN_PROGRESS
      */
     @RequiresFeature(PackageManager.FEATURE_TELEPHONY_DATA)
     public int getDataState() {
@@ -13005,6 +13013,25 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface DataEnabledReason{}
 
+    /** @hide */
+    @IntDef({
+            DATA_ENABLED_REASON_UNKNOWN,
+            DATA_ENABLED_REASON_USER,
+            DATA_ENABLED_REASON_POLICY,
+            DATA_ENABLED_REASON_CARRIER,
+            DATA_ENABLED_REASON_THERMAL,
+            DATA_ENABLED_REASON_OVERRIDE
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface DataEnabledChangedReason{}
+
+    /**
+     * To indicate that data was enabled or disabled due to an unknown reason.
+     * Note that this is not a valid reason for {@link #setDataEnabledForReason(int, boolean)} and
+     * is only used to indicate that data enabled was changed.
+     */
+    public static final int DATA_ENABLED_REASON_UNKNOWN = -1;
+
     /**
      * To indicate that user enabled or disabled data.
      */
@@ -13032,6 +13059,13 @@
     public static final int DATA_ENABLED_REASON_THERMAL = 3;
 
     /**
+     * To indicate data was enabled or disabled due to {@link MobileDataPolicy} overrides.
+     * Note that this is not a valid reason for {@link #setDataEnabledForReason(int, boolean)} and
+     * is only used to indicate that data enabled was changed due to an override.
+     */
+    public static final int DATA_ENABLED_REASON_OVERRIDE = 4;
+
+    /**
      * Control of data connection and provide the reason triggering the data connection control.
      * This can be called for following reasons
      * <ol>
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index 9ed230a..4ff59b5 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -521,11 +521,11 @@
     private final boolean mAlwaysOn;
 
     /**
-     * Returns the MTU size of the IPv4 mobile interface to which the APN connected. Note this value
-     * is used only if MTU size is not provided in {@link DataCallResponse}.
+     * Returns the default MTU (Maximum Transmission Unit) size in bytes of the IPv4 routes brought
+     * up by this APN setting. Note this value will only be used when MTU size is not provided
+     * in {@link DataCallResponse#getMtuV4()} during network bring up.
      *
-     * @return the MTU size of the APN
-     * @hide
+     * @return the MTU size in bytes of the route.
      */
     public int getMtuV4() {
         return mMtuV4;
@@ -533,10 +533,10 @@
 
     /**
      * Returns the MTU size of the IPv6 mobile interface to which the APN connected. Note this value
-     * is used only if MTU size is not provided in {@link DataCallResponse}.
+     * will only be used when MTU size is not provided in {@link DataCallResponse#getMtuV6()}
+     * during network bring up.
      *
-     * @return the MTU size of the APN
-     * @hide
+     * @return the MTU size in bytes of the route.
      */
     public int getMtuV6() {
         return mMtuV6;
@@ -1753,25 +1753,25 @@
         }
 
         /**
-         * Set the MTU size of the IPv4 mobile interface to which the APN connected. Note this value
-         * is used only if MTU size is not provided in {@link DataCallResponse}.
+         * Set the default MTU (Maximum Transmission Unit) size in bytes of the IPv4 routes brought
+         * up by this APN setting. Note this value will only be used when MTU size is not provided
+         * in {@link DataCallResponse#getMtuV4()} during network bring up.
          *
-         * @param mtuV4 the MTU size to set for the APN
-         * @hide
+         * @param mtuV4 the MTU size in bytes of the route.
          */
-        public Builder setMtuV4(int mtuV4) {
+        public @NonNull Builder setMtuV4(int mtuV4) {
             this.mMtuV4 = mtuV4;
             return this;
         }
 
         /**
-         * Set the MTU size of the IPv6 mobile interface to which the APN connected. Note this value
-         * is used only if MTU size is not provided in {@link DataCallResponse}.
+         * Set the default MTU (Maximum Transmission Unit) size in bytes of the IPv6 routes brought
+         * up by this APN setting. Note this value will only be used when MTU size is not provided
+         * in {@link DataCallResponse#getMtuV6()} during network bring up.
          *
-         * @param mtuV6 the MTU size to set for the APN
-         * @hide
+         * @param mtuV6 the MTU size in bytes of the route.
          */
-        public Builder setMtuV6(int mtuV6) {
+        public @NonNull Builder setMtuV6(int mtuV6) {
             this.mMtuV6 = mtuV6;
             return this;
         }
@@ -1779,15 +1779,25 @@
         /**
          * Sets the profile id to which the APN saved in modem.
          *
-         * @param profileId the profile id to set for the APN
-         * @hide
+         * @param profileId the profile id to set for the APN.
          */
-        public Builder setProfileId(int profileId) {
+        public @NonNull Builder setProfileId(int profileId) {
             this.mProfileId = profileId;
             return this;
         }
 
         /**
+         * Set if the APN setting should be persistent/non-persistent in modem.
+         *
+         * @param isPersistent {@code true} if this APN setting should be persistent/non-persistent
+         * in modem.
+         * @return The same instance of the builder.
+         */
+        public @NonNull Builder setPersistent(boolean isPersistent) {
+            return setModemCognitive(isPersistent);
+        }
+
+        /**
          * Sets if the APN setting is to be set in modem.
          *
          * @param modemCognitive if the APN setting is to be set in modem
diff --git a/telephony/java/android/telephony/data/DataProfile.java b/telephony/java/android/telephony/data/DataProfile.java
index 479f057..a166a5d 100644
--- a/telephony/java/android/telephony/data/DataProfile.java
+++ b/telephony/java/android/telephony/data/DataProfile.java
@@ -38,8 +38,10 @@
 import java.util.Objects;
 
 /**
- * Description of a mobile data profile used for establishing
- * data connections.
+ * Description of a mobile data profile used for establishing data networks. The data profile
+ * consist an {@link ApnSetting} which is needed for 2G/3G/4G networks bring up, and a
+ * {@link TrafficDescriptor} contains additional information that can be used for 5G standalone
+ * network bring up.
  *
  * @hide
  */
@@ -113,7 +115,9 @@
 
     /**
      * @return Id of the data profile.
+     * @deprecated Use {@link #getApnSetting()} and {@link ApnSetting#getProfileId()} instead.
      */
+    @Deprecated
     public int getProfileId() {
         if (mApnSetting != null) {
             return mApnSetting.getProfileId();
@@ -124,9 +128,10 @@
     /**
      * @return The APN (Access Point Name) to establish data connection. This is a string
      * specifically defined by the carrier.
+     * @deprecated Use {@link #getApnSetting()} and {@link ApnSetting#getApnName()} instead.
      */
-    @NonNull
-    public String getApn() {
+    @Deprecated
+    public @NonNull String getApn() {
         if (mApnSetting != null) {
             return TextUtils.emptyIfNull(mApnSetting.getApnName());
         }
@@ -135,7 +140,9 @@
 
     /**
      * @return The connection protocol defined in 3GPP TS 27.007 section 10.1.1.
+     * @deprecated Use {@link #getApnSetting()} and {@link ApnSetting#getProtocol()} instead.
      */
+    @Deprecated
     public @ProtocolType int getProtocolType() {
         if (mApnSetting != null) {
             return mApnSetting.getProtocol();
@@ -145,7 +152,9 @@
 
     /**
      * @return The authentication protocol used for this PDP context.
+     * @deprecated Use {@link #getApnSetting()} and {@link ApnSetting#getAuthType()} instead.
      */
+    @Deprecated
     public @AuthType int getAuthType() {
         if (mApnSetting != null) {
             return mApnSetting.getAuthType();
@@ -154,10 +163,11 @@
     }
 
     /**
-     * @return The username for APN. Can be null.
+     * @return The username for APN.
+     * @deprecated Use {@link #getApnSetting()} and {@link ApnSetting#getUser()} instead.
      */
-    @Nullable
-    public String getUserName() {
+    @Deprecated
+    public @Nullable String getUserName() {
         if (mApnSetting != null) {
             return mApnSetting.getUser();
         }
@@ -165,10 +175,11 @@
     }
 
     /**
-     * @return The password for APN. Can be null.
+     * @return The password for APN.
+     * @deprecated Use {@link #getApnSetting()} and {@link ApnSetting#getPassword()} instead.
      */
-    @Nullable
-    public String getPassword() {
+    @Deprecated
+    public @Nullable String getPassword() {
         if (mApnSetting != null) {
             return mApnSetting.getPassword();
         }
@@ -232,7 +243,9 @@
 
     /**
      * @return The supported APN types bitmask.
+     * @deprecated Use {@link #getApnSetting()} and {@link ApnSetting#getApnTypeBitmask()} instead.
      */
+    @Deprecated
     public @ApnType int getSupportedApnTypesBitmask() {
         if (mApnSetting != null) {
             return mApnSetting.getApnTypeBitmask();
@@ -242,7 +255,9 @@
 
     /**
      * @return The connection protocol on roaming network defined in 3GPP TS 27.007 section 10.1.1.
+     * @deprecated Use {@link #getApnSetting()} and {@link ApnSetting#getRoamingProtocol()} instead.
      */
+    @Deprecated
     public @ProtocolType int getRoamingProtocolType() {
         if (mApnSetting != null) {
             return mApnSetting.getRoamingProtocol();
@@ -252,7 +267,10 @@
 
     /**
      * @return The bearer bitmask indicating the applicable networks for this data profile.
+     * @deprecated use {@link #getApnSetting()} and {@link ApnSetting#getNetworkTypeBitmask()}
+     * instead.
      */
+    @Deprecated
     public @NetworkTypeBitMask int getBearerBitmask() {
         if (mApnSetting != null) {
             return mApnSetting.getNetworkTypeBitmask();
@@ -262,7 +280,8 @@
 
     /**
      * @return The maximum transmission unit (MTU) size in bytes.
-     * @deprecated use {@link #getMtuV4} or {@link #getMtuV6} instead.
+     * @deprecated use {@link #getApnSetting()} and {@link ApnSetting#getMtuV4()}/
+     * {@link ApnSetting#getMtuV6()} instead.
      */
     @Deprecated
     public int getMtu() {
@@ -272,7 +291,9 @@
     /**
      * This replaces the deprecated method getMtu.
      * @return The maximum transmission unit (MTU) size in bytes, for IPv4.
+     * @deprecated use {@link #getApnSetting()} and {@link ApnSetting#getMtuV4()} instead.
      */
+    @Deprecated
     public int getMtuV4() {
         if (mApnSetting != null) {
             return mApnSetting.getMtuV4();
@@ -282,7 +303,9 @@
 
     /**
      * @return The maximum transmission unit (MTU) size in bytes, for IPv6.
+     * @deprecated use {@link #getApnSetting()} and {@link ApnSetting#getMtuV6()} instead.
      */
+    @Deprecated
     public int getMtuV6() {
         if (mApnSetting != null) {
             return mApnSetting.getMtuV6();
@@ -292,7 +315,9 @@
 
     /**
      * @return {@code true} if modem must persist this data profile.
+     * @deprecated Use {@link #getApnSetting()} and {@link ApnSetting#isPersistent()} instead.
      */
+    @Deprecated
     public boolean isPersistent() {
         if (mApnSetting != null) {
             return mApnSetting.isPersistent();
@@ -320,16 +345,16 @@
     }
 
     /**
-     * @return The APN setting
-     * @hide TODO: Remove before T is released.
+     * @return The APN setting {@link ApnSetting}, which is used to establish data network on
+     * 2G/3G/4G.
      */
     public @Nullable ApnSetting getApnSetting() {
         return mApnSetting;
     }
 
     /**
-     * @return The traffic descriptor
-     * @hide TODO: Remove before T is released.
+     * @return The traffic descriptor {@link TrafficDescriptor}, which can be used to establish
+     * data network on 5G.
      */
     public @Nullable TrafficDescriptor getTrafficDescriptor() {
         return mTrafficDescriptor;
@@ -539,7 +564,10 @@
          *
          * @param profileId Network domain.
          * @return The same instance of the builder.
+         * @deprecated use {@link #setApnSetting(ApnSetting)} and
+         * {@link ApnSetting.Builder#setProfileId(int)} instead.
          */
+        @Deprecated
         public @NonNull Builder setProfileId(int profileId) {
             mProfileId = profileId;
             return this;
@@ -551,7 +579,10 @@
          *
          * @param apn Access point name
          * @return The same instance of the builder.
+         * @deprecated use {@link #setApnSetting(ApnSetting)} and
+         * {@link ApnSetting.Builder#setApnName(String)} instead.
          */
+        @Deprecated
         public @NonNull Builder setApn(@NonNull String apn) {
             mApn = apn;
             return this;
@@ -562,7 +593,10 @@
          *
          * @param protocolType The connection protocol defined in 3GPP TS 27.007 section 10.1.1.
          * @return The same instance of the builder.
+         * @deprecated use {@link #setApnSetting(ApnSetting)} and
+         * {@link ApnSetting.Builder#setProtocol(int)} instead.
          */
+        @Deprecated
         public @NonNull Builder setProtocolType(@ProtocolType int protocolType) {
             mProtocolType = protocolType;
             return this;
@@ -573,7 +607,10 @@
          *
          * @param authType The authentication type
          * @return The same instance of the builder.
+         * @deprecated use {@link #setApnSetting(ApnSetting)} and
+         * {@link ApnSetting.Builder#setAuthType(int)} instead.
          */
+        @Deprecated
         public @NonNull Builder setAuthType(@AuthType int authType) {
             mAuthType = authType;
             return this;
@@ -584,7 +621,10 @@
          *
          * @param userName The user name
          * @return The same instance of the builder.
+         * @deprecated use {@link #setApnSetting(ApnSetting)} and
+         * {@link ApnSetting.Builder#setUser(String)} instead.
          */
+        @Deprecated
         public @NonNull Builder setUserName(@NonNull String userName) {
             mUserName = userName;
             return this;
@@ -595,7 +635,10 @@
          *
          * @param password The password
          * @return The same instance of the builder.
+         * @deprecated use {@link #setApnSetting(ApnSetting)} and
+         * {@link ApnSetting.Builder#setPassword(String)} (int)} instead.
          */
+        @Deprecated
         public @NonNull Builder setPassword(@NonNull String password) {
             mPassword = password;
             return this;
@@ -628,7 +671,10 @@
          *
          * @param supportedApnTypesBitmask The supported APN types bitmask.
          * @return The same instance of the builder.
+         * @deprecated use {@link #setApnSetting(ApnSetting)} and
+         * {@link ApnSetting.Builder#setApnTypeBitmask(int)} instead.
          */
+        @Deprecated
         public @NonNull Builder setSupportedApnTypesBitmask(@ApnType int supportedApnTypesBitmask) {
             mSupportedApnTypesBitmask = supportedApnTypesBitmask;
             return this;
@@ -639,7 +685,10 @@
          *
          * @param protocolType The connection protocol defined in 3GPP TS 27.007 section 10.1.1.
          * @return The same instance of the builder.
+         * @deprecated use {@link #setApnSetting(ApnSetting)} and
+         * {@link ApnSetting.Builder#setRoamingProtocol(int)} instead.
          */
+        @Deprecated
         public @NonNull Builder setRoamingProtocolType(@ProtocolType int protocolType) {
             mRoamingProtocolType = protocolType;
             return this;
@@ -651,7 +700,10 @@
          * @param bearerBitmask The bearer bitmask indicating the applicable networks for this data
          * profile.
          * @return The same instance of the builder.
+         * @deprecated use {@link #setApnSetting(ApnSetting)} and
+         * {@link ApnSetting.Builder#setNetworkTypeBitmask(int)} instead.
          */
+        @Deprecated
         public @NonNull Builder setBearerBitmask(@NetworkTypeBitMask int bearerBitmask) {
             mBearerBitmask = bearerBitmask;
             return this;
@@ -662,7 +714,9 @@
          *
          * @param mtu The maximum transmission unit (MTU) size in bytes.
          * @return The same instance of the builder.
-         * @deprecated use {@link #setApnSetting(ApnSetting)} instead.
+         * @deprecated use {@link #setApnSetting(ApnSetting)} and
+         * {@link ApnSetting.Builder#setMtuV4(int)}/{@link ApnSetting.Builder#setMtuV6(int)}
+         * instead.
          */
         @Deprecated
         public @NonNull Builder setMtu(int mtu) {
@@ -672,11 +726,13 @@
 
         /**
          * Set the maximum transmission unit (MTU) size in bytes, for IPv4.
-         * This replaces the deprecated method setMtu.
          *
          * @param mtu The maximum transmission unit (MTU) size in bytes.
          * @return The same instance of the builder.
+         * @deprecated Use {{@link #setApnSetting(ApnSetting)}} and
+         * {@link ApnSetting.Builder#setMtuV4(int)} instead.
          */
+        @Deprecated
         public @NonNull Builder setMtuV4(int mtu) {
             mMtuV4 = mtu;
             return this;
@@ -687,7 +743,10 @@
          *
          * @param mtu The maximum transmission unit (MTU) size in bytes.
          * @return The same instance of the builder.
+         * @deprecated Use {{@link #setApnSetting(ApnSetting)}} and
+         * {@link ApnSetting.Builder#setMtuV6(int)} instead.
          */
+        @Deprecated
         public @NonNull Builder setMtuV6(int mtu) {
             mMtuV6 = mtu;
             return this;
@@ -712,19 +771,23 @@
          * @param isPersistent {@code true} if this data profile was used to bring up the last
          * default (i.e internet) data connection successfully.
          * @return The same instance of the builder.
+         * @deprecated Use {{@link #setApnSetting(ApnSetting)}} and
+         * {@link ApnSetting.Builder#setPersistent(boolean)} instead.
          */
+        @Deprecated
         public @NonNull Builder setPersistent(boolean isPersistent) {
             mPersistent = isPersistent;
             return this;
         }
 
         /**
-         * Set APN setting.
+         * Set the APN setting. Note that if an APN setting is not set here, then either
+         * {@link #setApn(String)} or {@link #setTrafficDescriptor(TrafficDescriptor)} must be
+         * called. Otherwise {@link IllegalArgumentException} will be thrown when {@link #build()}
+         * the data profile.
          *
-         * @param apnSetting APN setting
-         * @return The same instance of the builder
-         *
-         * @hide // TODO: Remove before T is released.
+         * @param apnSetting The APN setting.
+         * @return The same instance of the builder.
          */
         public @NonNull Builder setApnSetting(@NonNull ApnSetting apnSetting) {
             mApnSetting = apnSetting;
@@ -732,12 +795,13 @@
         }
 
         /**
-         * Set traffic descriptor.
+         * Set the traffic descriptor. Note that if a traffic descriptor is not set here, then
+         * either {@link #setApnSetting(ApnSetting)} or {@link #setApn(String)} must be called.
+         * Otherwise {@link IllegalArgumentException} will be thrown when {@link #build()} the data
+         * profile.
          *
-         * @param trafficDescriptor Traffic descriptor
-         * @return The same instance of the builder
-         *
-         * @hide // TODO: Remove before T is released.
+         * @param trafficDescriptor The traffic descriptor.
+         * @return The same instance of the builder.
          */
         public @NonNull Builder setTrafficDescriptor(@NonNull TrafficDescriptor trafficDescriptor) {
             mTrafficDescriptor = trafficDescriptor;
@@ -745,9 +809,9 @@
         }
 
         /**
-         * Build the DataProfile object
+         * Build the DataProfile object.
          *
-         * @return The data profile object
+         * @return The data profile object.
          */
         public @NonNull DataProfile build() {
             if (mApnSetting == null && mApn != null) {
diff --git a/telephony/java/android/telephony/euicc/EuiccCardManager.java b/telephony/java/android/telephony/euicc/EuiccCardManager.java
index 4efd159..f614988 100644
--- a/telephony/java/android/telephony/euicc/EuiccCardManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccCardManager.java
@@ -262,48 +262,12 @@
      * @param refresh  Whether sending the REFRESH command to modem.
      * @param executor The executor through which the callback should be invoked.
      * @param callback The callback to get the result code.
-     * @deprecated instead use {@link #disableProfile(String, String, int, boolean, Executor,
-     * ResultCallback)}
      */
-    @Deprecated
     public void disableProfile(String cardId, String iccid, boolean refresh,
             @CallbackExecutor Executor executor, ResultCallback<Void> callback) {
         try {
             getIEuiccCardController().disableProfile(mContext.getOpPackageName(), cardId, iccid,
-                    TelephonyManager.DEFAULT_PORT_INDEX, refresh,
-                    new IDisableProfileCallback.Stub() {
-                        @Override
-                        public void onComplete(int resultCode) {
-                            final long token = Binder.clearCallingIdentity();
-                            try {
-                                executor.execute(() -> callback.onComplete(resultCode, null));
-                            } finally {
-                                Binder.restoreCallingIdentity(token);
-                            }
-                        }
-                    });
-        } catch (RemoteException e) {
-            Log.e(TAG, "Error calling disableProfile", e);
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Disables the profile of the given ICCID.
-     *
-     * @param cardId    The Id of the eUICC.
-     * @param iccid     The iccid of the profile.
-     * @param portIndex the Port index is the unique index referring to a port.
-     * @param refresh   Whether sending the REFRESH command to modem.
-     * @param executor  The executor through which the callback should be invoked.
-     * @param callback  The callback to get the result code.
-     */
-    public void disableProfile(@Nullable String cardId, @Nullable String iccid, int portIndex,
-            boolean refresh, @NonNull @CallbackExecutor Executor executor,
-            @NonNull ResultCallback<Void> callback) {
-        try {
-            getIEuiccCardController().disableProfile(mContext.getOpPackageName(), cardId, iccid,
-                    portIndex, refresh, new IDisableProfileCallback.Stub() {
+                    refresh, new IDisableProfileCallback.Stub() {
                         @Override
                         public void onComplete(int resultCode) {
                             final long token = Binder.clearCallingIdentity();
diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java
index 389cc6d..2e5402c5 100644
--- a/telephony/java/android/telephony/euicc/EuiccManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccManager.java
@@ -16,7 +16,6 @@
 package android.telephony.euicc;
 
 import android.Manifest;
-import android.annotation.CallbackExecutor;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -30,7 +29,6 @@
 import android.content.Intent;
 import android.content.IntentSender;
 import android.content.pm.PackageManager;
-import android.os.Binder;
 import android.os.Bundle;
 import android.os.RemoteException;
 import android.telephony.TelephonyFrameworkInitializer;
@@ -38,13 +36,11 @@
 import android.telephony.euicc.EuiccCardManager.ResetOption;
 
 import com.android.internal.telephony.euicc.IEuiccController;
-import com.android.internal.telephony.euicc.IResultCallback;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.Collections;
 import java.util.List;
-import java.util.concurrent.Executor;
 import java.util.stream.Collectors;
 
 /**
@@ -221,20 +217,6 @@
             "android.telephony.euicc.action.START_EUICC_ACTIVATION";
 
     /**
-     * Result codes passed to the ResultListener by
-     * {@link #switchToSubscription(int, int, Executor, ResultListener)}
-     *
-     * @hide
-     */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(prefix = {"EMBEDDED_SUBSCRIPTION_RESULT_"}, value = {
-            EMBEDDED_SUBSCRIPTION_RESULT_OK,
-            EMBEDDED_SUBSCRIPTION_RESULT_ERROR,
-            EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR
-    })
-    public @interface ResultCode{}
-
-    /**
      * Result code for an operation indicating that the operation succeeded.
      */
     public static final int EMBEDDED_SUBSCRIPTION_RESULT_OK = 0;
@@ -1147,7 +1129,7 @@
      * @param callbackIntent a PendingIntent to launch when the operation completes.
      *
      * @deprecated From T, callers should use
-     * {@link #switchToSubscription(int, int, Executor, ResultListener)} instead to specify a port
+     * {@link #switchToSubscription(int, int, PendingIntent)} instead to specify a port
      * index on the card to switch to.
      */
     @Deprecated
@@ -1190,47 +1172,24 @@
      *     permission, or the calling app must be authorized to manage the active subscription on
      *     the target eUICC.
      * @param portIndex the index of the port to target for the enabled subscription
-     * @param executor an Executor on which to run the callback
-     * @param callback a {@link ResultListener} which will run when the operation completes
+     * @param callbackIntent a PendingIntent to launch when the operation completes.
      */
     @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
     public void switchToSubscription(int subscriptionId, int portIndex,
-            @NonNull @CallbackExecutor Executor executor,
-            @NonNull ResultListener callback) {
+            @NonNull PendingIntent callbackIntent) {
         if (!isEnabled()) {
-            sendUnavailableErrorToCallback(executor, callback);
+            sendUnavailableError(callbackIntent);
             return;
         }
         try {
-            IResultCallback internalCallback = new IResultCallback.Stub() {
-                @Override
-                public void onComplete(int result, Intent resultIntent) {
-                    executor.execute(() -> Binder.withCleanCallingIdentity(
-                            () -> callback.onComplete(result, resultIntent)));
-                }
-            };
-            getIEuiccController().switchToSubscriptionWithPort(mCardId, portIndex,
-                    subscriptionId, mContext.getOpPackageName(), internalCallback);
+            getIEuiccController().switchToSubscriptionWithPort(mCardId,
+                    subscriptionId, portIndex, mContext.getOpPackageName(), callbackIntent);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
     }
 
     /**
-     * Callback to receive the result of an EuiccManager API.
-     */
-    public interface ResultListener {
-        /**
-         * Called on completion of some operation.
-         * @param resultCode representing success or specific failure of the operation
-         *                   (See {@link ResultCode})
-         * @param resultIntent an intent used to start a resolution activity when an error
-         *                     occurs that can be resolved by the user
-         */
-        void onComplete(@ResultCode int resultCode, @Nullable Intent resultIntent);
-    }
-
-    /**
      * Update the nickname for the given subscription.
      *
      * <p>Requires that the calling app has carrier privileges according to the metadata of the
@@ -1501,13 +1460,6 @@
         }
     }
 
-    private static void sendUnavailableErrorToCallback(@NonNull Executor executor,
-            ResultListener callback) {
-        Integer result = EMBEDDED_SUBSCRIPTION_RESULT_ERROR;
-        executor.execute(() ->
-                Binder.withCleanCallingIdentity(() -> callback.onComplete(result, null)));
-    }
-
     private static IEuiccController getIEuiccController() {
         return IEuiccController.Stub.asInterface(
                 TelephonyFrameworkInitializer
diff --git a/telephony/java/android/telephony/ims/ImsCallProfile.java b/telephony/java/android/telephony/ims/ImsCallProfile.java
index 93e1058..7e2d80e 100644
--- a/telephony/java/android/telephony/ims/ImsCallProfile.java
+++ b/telephony/java/android/telephony/ims/ImsCallProfile.java
@@ -317,6 +317,10 @@
      * Payphone presentation for Originating Identity.
      */
     public static final int OIR_PRESENTATION_PAYPHONE = 4;
+    /**
+     * Unavailable presentation for Originating Identity.
+     */
+    public static final int OIR_PRESENTATION_UNAVAILABLE = 5;
 
     //Values for EXTRA_DIALSTRING
     /**
@@ -989,6 +993,8 @@
                 return ImsCallProfile.OIR_PRESENTATION_PAYPHONE;
             case PhoneConstants.PRESENTATION_UNKNOWN:
                 return ImsCallProfile.OIR_PRESENTATION_UNKNOWN;
+            case PhoneConstants.PRESENTATION_UNAVAILABLE:
+                return ImsCallProfile.OIR_PRESENTATION_UNAVAILABLE;
             default:
                 return ImsCallProfile.OIR_DEFAULT;
         }
@@ -1017,6 +1023,8 @@
                 return PhoneConstants.PRESENTATION_ALLOWED;
             case ImsCallProfile.OIR_PRESENTATION_PAYPHONE:
                 return PhoneConstants.PRESENTATION_PAYPHONE;
+            case ImsCallProfile.OIR_PRESENTATION_UNAVAILABLE:
+                return PhoneConstants.PRESENTATION_UNAVAILABLE;
             case ImsCallProfile.OIR_PRESENTATION_UNKNOWN:
                 return PhoneConstants.PRESENTATION_UNKNOWN;
             default:
diff --git a/telephony/java/com/android/internal/telephony/PhoneConstants.java b/telephony/java/com/android/internal/telephony/PhoneConstants.java
index f650246..813e80e 100644
--- a/telephony/java/com/android/internal/telephony/PhoneConstants.java
+++ b/telephony/java/com/android/internal/telephony/PhoneConstants.java
@@ -95,6 +95,7 @@
     public static final int PRESENTATION_UNKNOWN = 3;    // no specified or unknown by network
     @UnsupportedAppUsage
     public static final int PRESENTATION_PAYPHONE = 4;   // show pay phone info
+    public static final int PRESENTATION_UNAVAILABLE = 5;   // show unavailable
 
     public static final String PHONE_NAME_KEY = "phoneName";
     public static final String DATA_NETWORK_TYPE_KEY = "networkType";
diff --git a/telephony/java/com/android/internal/telephony/euicc/IEuiccCardController.aidl b/telephony/java/com/android/internal/telephony/euicc/IEuiccCardController.aidl
index 1734c98..928223a 100644
--- a/telephony/java/com/android/internal/telephony/euicc/IEuiccCardController.aidl
+++ b/telephony/java/com/android/internal/telephony/euicc/IEuiccCardController.aidl
@@ -47,8 +47,8 @@
         in IGetProfileCallback callback);
     oneway void getEnabledProfile(String callingPackage, String cardId, int portIndex,
         in IGetProfileCallback callback);
-    oneway void disableProfile(String callingPackage, String cardId, String iccid, int portIndex,
-            boolean refresh, in IDisableProfileCallback callback);
+    oneway void disableProfile(String callingPackage, String cardId, String iccid, boolean refresh,
+        in IDisableProfileCallback callback);
     oneway void switchToProfile(String callingPackage, String cardId, String iccid, int portIndex,
             boolean refresh, in ISwitchToProfileCallback callback);
     oneway void setNickname(String callingPackage, String cardId, String iccid, String nickname,
diff --git a/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl b/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl
index 7f5982f..dda95b1 100644
--- a/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl
+++ b/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl
@@ -22,8 +22,6 @@
 import android.telephony.euicc.DownloadableSubscription;
 import android.telephony.euicc.EuiccInfo;
 
-import com.android.internal.telephony.euicc.IResultCallback;
-
 import java.util.List;
 
 /** @hide */
@@ -45,8 +43,8 @@
         in PendingIntent callbackIntent);
     oneway void switchToSubscription(int cardId, int subscriptionId, String callingPackage,
         in PendingIntent callbackIntent);
-    oneway void switchToSubscriptionWithPort(int cardId, int portIndex, int subscriptionId,
-        String callingPackage, in IResultCallback callback);
+    oneway void switchToSubscriptionWithPort(int cardId, int subscriptionId, int portIndex,
+        String callingPackage, in PendingIntent callbackIntent);
     oneway void updateSubscriptionNickname(int cardId, int subscriptionId, String nickname,
         String callingPackage, in PendingIntent callbackIntent);
     oneway void eraseSubscriptions(int cardId, in PendingIntent callbackIntent);
diff --git a/test-legacy/Android.mk b/test-legacy/Android.mk
index ce5e4cf..284008c 100644
--- a/test-legacy/Android.mk
+++ b/test-legacy/Android.mk
@@ -41,6 +41,6 @@
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
 # Archive a copy of the classes.jar in SDK build.
-$(call dist-for-goals,sdk win_sdk,$(full_classes_jar):android.test.legacy.jar)
+$(call dist-for-goals,sdk,$(full_classes_jar):android.test.legacy.jar)
 
 endif  # not TARGET_BUILD_APPS not TARGET_BUILD_PDK=true
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 7076a07..8de38f6 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
@@ -83,7 +83,7 @@
     override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
 
     /** {@inheritDoc} */
-    @Presubmit
+    @FlakyTest(bugId = 206753786)
     @Test
     override fun statusBarLayerRotatesScales() {
         // This test doesn't work in shell transitions because of b/206753786
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 b5d01ef..22acc03 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
@@ -82,7 +82,7 @@
     override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
 
     /** {@inheritDoc} */
-    @Presubmit
+    @FlakyTest(bugId = 206753786)
     @Test
     override fun statusBarLayerRotatesScales() {
         // This test doesn't work in shell transitions because of b/206753786
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt
index 59e8dc8..8fe0029 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt
@@ -37,16 +37,21 @@
         .launcherStrategy
 ) : StandardAppHelper(instr, launcherName, component, launcherStrategy) {
     fun openSecondActivity(device: UiDevice, wmHelper: WindowManagerStateHelper) {
-        val button = device.wait(
-                Until.findObject(By.res(getPackage(), "launch_second_activity")),
-                FIND_TIMEOUT)
+        val launchActivityButton = By.res(getPackage(), LAUNCH_SECOND_ACTIVITY)
+        val button = device.wait(Until.findObject(launchActivityButton), FIND_TIMEOUT)
 
         require(button != null) {
             "Button not found, this usually happens when the device " +
                     "was left in an unknown state (e.g. in split screen)"
         }
         button.click()
+
+        device.wait(Until.gone(launchActivityButton), FIND_TIMEOUT)
         wmHelper.waitForAppTransitionIdle()
         wmHelper.waitForFullScreenApp(component)
     }
+
+    companion object {
+        private const val LAUNCH_SECOND_ACTIVITY = "launch_second_activity"
+    }
 }
\ No newline at end of file
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 f12e4ae..56879c9 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
@@ -20,6 +20,7 @@
 import android.platform.test.annotations.Presubmit
 import android.view.Surface
 import android.view.WindowManagerPolicyConstants
+import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.server.wm.flicker.FlickerBuilderProvider
@@ -154,7 +155,7 @@
     @Test
     fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales()
 
-    @Presubmit
+    @FlakyTest(bugId = 206753786)
     @Test
     fun statusBarLayerRotatesScales() {
         // This test doesn't work in shell transitions because of b/206753786
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 0529fdd..c28466c 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
@@ -20,6 +20,7 @@
 import android.platform.test.annotations.Presubmit
 import android.view.Surface
 import android.view.WindowManagerPolicyConstants
+import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.server.wm.flicker.FlickerBuilderProvider
@@ -156,7 +157,7 @@
     @Test
     fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales()
 
-    @Presubmit
+    @FlakyTest(bugId = 206753786)
     @Test
     fun statusBarLayerRotatesScales() {
         // This test doesn't work in shell transitions because of b/206753786
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 d975cf4..c7f1b99 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
@@ -132,7 +132,7 @@
         testSpec.navBarLayerRotatesAndScales()
     }
 
-    @Presubmit
+    @FlakyTest(bugId = 206753786)
     @Test
     fun statusBarLayerRotatesScales() {
         // This test doesn't work in shell transitions because of b/206753786
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 facca94..46ed0ad 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
@@ -20,6 +20,7 @@
 import android.platform.test.annotations.Presubmit
 import android.view.Surface
 import android.view.WindowManagerPolicyConstants
+import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.server.wm.flicker.FlickerBuilderProvider
@@ -149,7 +150,7 @@
     @Test
     fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales()
 
-    @Presubmit
+    @FlakyTest(bugId = 206753786)
     @Test
     fun statusBarLayerRotatesScales() {
         // This test doesn't work in shell transitions because of b/206753786
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 3ef4e4c..ebe4be2 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
@@ -20,6 +20,7 @@
 import android.platform.test.annotations.Presubmit
 import android.view.Surface
 import android.view.WindowManagerPolicyConstants
+import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.server.wm.flicker.FlickerBuilderProvider
@@ -127,7 +128,7 @@
     @Test
     fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales()
 
-    @Presubmit
+    @FlakyTest(bugId = 206753786)
     @Test
     fun statusBarLayerRotatesScales() {
         // This test doesn't work in shell transitions because of b/206753786
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 84e78ec..f6e5adc 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
@@ -217,7 +217,7 @@
     @Test
     fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales()
 
-    @Presubmit
+    @FlakyTest(bugId = 206753786)
     @Test
     fun statusBarLayerRotatesScales() {
         // This test doesn't work in shell transitions because of b/206753786
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 a7a9fe2..19e2c92 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
@@ -86,8 +86,8 @@
                 // [Step1]: Swipe right from imeTestApp to testApp task
                 createTag(TAG_IME_VISIBLE)
                 val displayBounds = WindowUtils.getDisplayBounds(testSpec.startRotation)
-                device.swipe(0, displayBounds.bounds.height(),
-                        displayBounds.bounds.width(), displayBounds.bounds.height(), 50)
+                device.swipe(0, displayBounds.bounds.height,
+                        displayBounds.bounds.width, displayBounds.bounds.height, 50)
 
                 wmHelper.waitForFullScreenApp(testApp.component)
                 wmHelper.waitForAppTransitionIdle()
@@ -96,8 +96,8 @@
             transitions {
                 // [Step2]: Swipe left to back to imeTestApp task
                 val displayBounds = WindowUtils.getDisplayBounds(testSpec.startRotation)
-                device.swipe(displayBounds.bounds.width(), displayBounds.bounds.height(),
-                        0, displayBounds.bounds.height(), 50)
+                device.swipe(displayBounds.bounds.width, displayBounds.bounds.height,
+                        0, displayBounds.bounds.height, 50)
                 wmHelper.waitForFullScreenApp(imeTestApp.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 32feccd..eef7b57 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
@@ -81,7 +81,7 @@
         }
 
     /** {@inheritDoc} */
-    @Presubmit
+    @FlakyTest(bugId = 206753786)
     @Test
     override fun statusBarLayerRotatesScales() {
         // This test doesn't work in shell transitions because of b/206753786
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 53b5354..aac4812 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
@@ -98,7 +98,7 @@
         }
 
     /** {@inheritDoc} */
-    @Presubmit
+    @FlakyTest(bugId = 206753786)
     @Test
     override fun statusBarLayerRotatesScales() {
         // This test doesn't work in shell transitions because of b/206753786
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 3914ef6..6e5c600 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
@@ -188,7 +188,7 @@
     }
 
     /** {@inheritDoc} */
-    @Presubmit
+    @FlakyTest(bugId = 206753786)
     @Test
     fun statusBarLayerPositionAtEnd() {
         // This test doesn't work in shell transitions because of b/206753786
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 619f5d2..dfa8f8e 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
@@ -85,7 +85,7 @@
         }
 
     /** {@inheritDoc} */
-    @Presubmit
+    @FlakyTest(bugId = 206753786)
     @Test
     override fun statusBarLayerRotatesScales() {
         // This test doesn't work in shell transitions because of b/206753786
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt
index 769cb1a..882e128 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt
@@ -148,22 +148,28 @@
         val displayBounds = WindowUtils.getDisplayBounds(testSpec.startRotation)
 
         testSpec.assertLayers {
-            this.coversExactly(displayBounds, LAUNCH_NEW_TASK_ACTIVITY)
+            this.invoke("LAUNCH_NEW_TASK_ACTIVITY coversExactly displayBounds") {
+                    it.visibleRegion(LAUNCH_NEW_TASK_ACTIVITY).coversExactly(displayBounds)
+                }
                 .isInvisible(bgColorLayer)
                 .then()
                 // Transitioning
                 .isVisible(bgColorLayer)
                 .then()
                 // Fully transitioned to simple SIMPLE_ACTIVITY
-                .coversExactly(displayBounds, SIMPLE_ACTIVITY)
+                .invoke("SIMPLE_ACTIVITY coversExactly displayBounds") {
+                    it.visibleRegion(SIMPLE_ACTIVITY).coversExactly(displayBounds)
+                }
                 .isInvisible(bgColorLayer)
                 .then()
                 // Transitioning back
                 .isVisible(bgColorLayer)
                 .then()
                 // Fully transitioned back to LAUNCH_NEW_TASK_ACTIVITY
+                .invoke("LAUNCH_NEW_TASK_ACTIVITY coversExactly displayBounds") {
+                    it.visibleRegion(LAUNCH_NEW_TASK_ACTIVITY).coversExactly(displayBounds)
+                }
                 .isInvisible(bgColorLayer)
-                .coversExactly(displayBounds, LAUNCH_NEW_TASK_ACTIVITY)
         }
     }
 
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
index 8f8951b..01fce05 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt
@@ -31,7 +31,6 @@
 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.isShellTransitionsEnabled
 import com.android.server.wm.flicker.navBarLayerIsVisible
 import com.android.server.wm.flicker.navBarLayerRotatesAndScales
@@ -39,6 +38,7 @@
 import com.android.server.wm.flicker.statusBarLayerIsVisible
 import com.android.server.wm.flicker.statusBarWindowIsVisible
 import com.android.server.wm.traces.common.FlickerComponentName
+import com.android.server.wm.traces.common.Rect
 import org.junit.Assume
 import org.junit.FixMethodOrder
 import org.junit.Test
@@ -68,8 +68,6 @@
     private val testApp1 = SimpleAppHelper(instrumentation)
     private val testApp2 = NonResizeableAppHelper(instrumentation)
 
-    private val startDisplayBounds = WindowUtils.getDisplayBounds(testSpec.startRotation)
-
     @FlickerBuilderProvider
     fun buildFlicker(): FlickerBuilder {
         return FlickerBuilder(instrumentation).apply {
@@ -81,15 +79,20 @@
                     testApp2.launchViaIntent(wmHelper)
                     wmHelper.waitForFullScreenApp(testApp2.component)
 
+                    startDisplayBounds = wmHelper.currentState.layerState
+                        .displays.firstOrNull { !it.isVirtual }
+                        ?.layerStackSpace
+                        ?: error("Display not found")
+
                     // 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,
+                            startDisplayBounds.right / 3,
+                            startDisplayBounds.bottom,
+                            2 * startDisplayBounds.right / 3,
+                            startDisplayBounds.bottom,
                             if (testSpec.isLandscapeOrSeascapeAtStart) 75 else 30
                     )
 
@@ -103,10 +106,10 @@
                 // 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,
+                        2 * startDisplayBounds.right / 3,
+                        startDisplayBounds.bottom,
+                        startDisplayBounds.right / 3,
+                        startDisplayBounds.bottom,
                         if (testSpec.isLandscapeOrSeascapeAtStart) 75 else 30
                 )
 
@@ -133,7 +136,8 @@
         // This test doesn't work in shell transitions because of b/209936664
         Assume.assumeFalse(isShellTransitionsEnabled)
         testSpec.assertWmStart {
-            this.frameRegion(testApp1.component).coversExactly(startDisplayBounds)
+            this.frameRegion(testApp1.component, FlickerComponentName.LETTERBOX)
+                .coversExactly(startDisplayBounds)
         }
     }
 
@@ -188,7 +192,8 @@
         // This test doesn't work in shell transitions because of b/209936664
         Assume.assumeFalse(isShellTransitionsEnabled)
         testSpec.assertLayersEnd {
-            this.visibleRegion(testApp2.component).coversExactly(startDisplayBounds)
+            this.visibleRegion(testApp2.component, FlickerComponentName.LETTERBOX)
+                .coversExactly(startDisplayBounds)
         }
     }
 
@@ -372,6 +377,8 @@
     }
 
     companion object {
+        private var startDisplayBounds = Rect.EMPTY
+
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
         fun getParams(): Collection<FlickerTestParameter> {
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 c18798f..0879b98 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
@@ -165,7 +165,7 @@
     /**
      * Checks the position of the status bar at the start and end of the transition
      */
-    @Presubmit
+    @FlakyTest(bugId = 206753786)
     @Test
     fun statusBarLayerRotatesScales() {
         // This test doesn't work in shell transitions because of b/206753786
diff --git a/tests/HwAccelerationTest/Android.bp b/tests/HwAccelerationTest/Android.bp
index e618ed1..51848f2 100644
--- a/tests/HwAccelerationTest/Android.bp
+++ b/tests/HwAccelerationTest/Android.bp
@@ -32,6 +32,10 @@
         "**/*.java",
         "**/*.kt",
     ],
+    static_libs: [
+        "androidx.cardview_cardview",
+    ],
+
     platform_apis: true,
     certificate: "platform",
 }
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index 22fe424..b0ccbd1 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -789,6 +789,15 @@
             </intent-filter>
         </activity>
 
+        <activity android:name="RenderEffectViewActivity"
+                  android:label="RenderEffect/View"
+                  android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="com.android.test.hwui.TEST"/>
+            </intent-filter>
+        </activity>
+
         <activity android:name="StretchShaderActivity"
                   android:label="RenderEffect/Stretch"
                   android:exported="true">
diff --git a/tests/HwAccelerationTest/res/drawable-nodpi/scratches.png b/tests/HwAccelerationTest/res/drawable-nodpi/scratches.png
new file mode 100644
index 0000000..cc8adf1
--- /dev/null
+++ b/tests/HwAccelerationTest/res/drawable-nodpi/scratches.png
Binary files differ
diff --git a/tests/HwAccelerationTest/res/drawable-nodpi/weather_2.jpg b/tests/HwAccelerationTest/res/drawable-nodpi/weather_2.jpg
new file mode 100644
index 0000000..b5aff10
--- /dev/null
+++ b/tests/HwAccelerationTest/res/drawable-nodpi/weather_2.jpg
Binary files differ
diff --git a/tests/HwAccelerationTest/res/layout/view_runtime_shader.xml b/tests/HwAccelerationTest/res/layout/view_runtime_shader.xml
new file mode 100644
index 0000000..b91377d
--- /dev/null
+++ b/tests/HwAccelerationTest/res/layout/view_runtime_shader.xml
@@ -0,0 +1,205 @@
+<?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.
+  -->
+
+<ScrollView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+    <LinearLayout
+        android:id="@+id/TopLayout"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingBottom="8dp"
+        android:orientation="vertical">
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_margin="16dp"
+            android:text="Sample Card #1"/>
+
+        <androidx.cardview.widget.CardView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_margin="8dp"
+            android:layout_marginBottom="16dp"
+            android:clickable="true"
+            android:focusable="true"
+            android:minHeight="148dp">
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="vertical">
+
+                <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:padding="16dp"
+                    android:paddingBottom="8dp">
+
+                    <ImageView
+                        android:layout_width="50dp"
+                        android:layout_height="50dp"
+                        android:layout_marginEnd="8dp"
+                        android:layout_marginRight="8dp"
+                        android:contentDescription="Logo"
+                        android:src="@drawable/icon"/>
+
+                    <LinearLayout
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:layout_weight="1.0"
+                        android:layout_marginStart="8dp"
+                        android:layout_marginLeft="8dp"
+                        android:orientation="vertical">
+                        <TextView
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:textStyle="bold"
+                            android:text="Image Transition"/>
+
+                        <TextView
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:layout_marginTop="8dp"
+                            android:ellipsize="end"
+                            android:maxLines="1"
+                            android:text="Touch the image to trigger the animation"/>
+                    </LinearLayout>
+                </LinearLayout>
+
+                <com.android.test.hwui.BitmapTransitionView
+                    android:layout_width="match_parent"
+                    android:layout_height="194dp"
+                    android:padding="8dp"/>
+
+            </LinearLayout>
+
+        </androidx.cardview.widget.CardView>
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_margin="16dp"
+            android:text="Sample Card #2"/>
+
+        <androidx.cardview.widget.CardView
+            android:id="@+id/CardView"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_margin="8dp"
+            android:layout_marginBottom="16dp"
+            android:clickable="true"
+            android:focusable="true"
+            android:minHeight="148dp">
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:paddingTop="16dp"
+                android:orientation="vertical">
+
+                <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:padding="16dp"
+                    android:paddingBottom="8dp">
+
+                    <ImageView
+                        android:layout_width="50dp"
+                        android:layout_height="50dp"
+                        android:layout_marginEnd="8dp"
+                        android:layout_marginRight="8dp"
+                        android:contentDescription="Logo"
+                        android:src="@drawable/icon"/>
+
+                    <LinearLayout
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:layout_weight="1.0"
+                        android:layout_marginStart="8dp"
+                        android:layout_marginLeft="8dp"
+                        android:orientation="vertical">
+                        <TextView
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:textStyle="bold"
+                            android:text="View Group Manipulation"/>
+
+                        <TextView
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:layout_marginTop="8dp"
+                            android:ellipsize="end"
+                            android:maxLines="1"
+                            android:text="Tap the card to trigger the animation"/>
+                    </LinearLayout>
+                </LinearLayout>
+
+                <ImageView
+                    android:layout_width="match_parent"
+                    android:layout_height="194dp"
+                    android:background="@android:color/transparent"
+                    android:src="@drawable/weather_2"/>
+
+                <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:padding="16dp"
+                    android:paddingBottom="8dp"
+                    android:orientation="vertical">
+
+                    <LinearLayout
+                        android:layout_width="match_parent"
+                        android:layout_height="wrap_content">
+                        <RatingBar
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:contentDescription="Card Rating"
+                            android:isIndicator="true"
+                            android:numStars="5"
+                            android:rating="4.5"
+
+                            android:stepSize="0.5"/>
+                        <TextView
+                            android:layout_width="wrap_content"
+                            android:layout_height="match_parent"
+                            android:gravity="center_vertical"
+                            android:text="Category 4.5 Storm"/>
+                    </LinearLayout>
+
+                    <TextView
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:layout_marginTop="8dp"
+                        android:maxLines="3"
+                        android:textIsSelectable="true"
+                        android:text="Lorem ipsum dolor sit amet, nec no nominavi scaevola. Per et
+                        sint sapientem, nobis perpetua salutandi mei te. Quo tamquam probatus
+                        reprehendunt in. Eos esse purto eruditi ea. Enim tation persius ut sea,
+                        eos ad consul populo. Ne eum solet altera. Cibo eligendi et est, electram
+                        theophrastus te vel eu."/>
+
+                </LinearLayout>
+
+            </LinearLayout>
+
+        </androidx.cardview.widget.CardView>
+    </LinearLayout>
+</ScrollView>
diff --git a/tests/HwAccelerationTest/res/values/styles.xml b/tests/HwAccelerationTest/res/values/styles.xml
index fa5437f..55f4dd69 100644
--- a/tests/HwAccelerationTest/res/values/styles.xml
+++ b/tests/HwAccelerationTest/res/values/styles.xml
@@ -41,4 +41,5 @@
         <item name="android:spotShadowAlpha">1</item>
         -->
     </style>
+
 </resources>
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/BitmapTransitionView.kt b/tests/HwAccelerationTest/src/com/android/test/hwui/BitmapTransitionView.kt
new file mode 100644
index 0000000..d3ad9e8
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/BitmapTransitionView.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.test.hwui
+
+import android.animation.ValueAnimator
+import android.content.Context
+import android.graphics.BitmapShader
+import android.graphics.Canvas
+import android.graphics.ImageDecoder
+import android.graphics.Matrix
+import android.graphics.Paint
+import android.graphics.RuntimeShader
+import android.graphics.Shader
+import android.util.AttributeSet
+import android.view.View
+
+class BitmapTransitionView @JvmOverloads constructor(
+    context: Context,
+    attrs: AttributeSet? = null,
+    defStyleAttr: Int = 0
+) : View(context, attrs, defStyleAttr) {
+
+    private val mPaint = Paint()
+    private val mImageA = ImageDecoder.decodeBitmap(
+            ImageDecoder.createSource(context.resources, R.drawable.large_photo))
+    private val mImageB = ImageDecoder.decodeBitmap(
+            ImageDecoder.createSource(context.resources, R.drawable.very_large_photo))
+    private val mShaderA = BitmapShader(mImageA, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
+    private val mShaderB = BitmapShader(mImageB, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
+    private val mShader = RuntimeShader(AGSL, false)
+    private var mCurrentProgress = -1f
+    private var mForwardProgress = true
+    private var mCurrentAnimator = ValueAnimator.ofFloat(-1f, 1f)
+
+    init {
+        isClickable = true
+
+        mCurrentAnimator.duration = 1500
+        mCurrentAnimator.addUpdateListener { animation ->
+            mCurrentProgress = animation.animatedValue as Float
+            postInvalidate()
+        }
+    }
+
+    override fun performClick(): Boolean {
+        if (super.performClick()) return true
+
+        if (mCurrentAnimator.isRunning) {
+            mCurrentAnimator.reverse()
+            return true
+        }
+
+        if (mForwardProgress) {
+            mCurrentAnimator.setFloatValues(-1f, 1f)
+            mForwardProgress = false
+        } else {
+            mCurrentAnimator.setFloatValues(1f, -1f)
+            mForwardProgress = true
+        }
+
+        mCurrentAnimator.start()
+        postInvalidate()
+        return true
+    }
+
+    override fun onSizeChanged(width: Int, height: Int, oldWidth: Int, oldHeight: Int) {
+        val matrixA = Matrix()
+        val matrixB = Matrix()
+
+        matrixA.postScale(width.toFloat() / mImageA.width, height.toFloat() / mImageA.height)
+        matrixB.postScale(width.toFloat() / mImageB.width, height.toFloat() / mImageB.height)
+
+        mShaderA.setLocalMatrix(matrixA)
+        mShaderB.setLocalMatrix(matrixB)
+    }
+
+    override fun onDraw(canvas: Canvas) {
+        super.onDraw(canvas)
+
+        mShader.setInputShader("imageA", mShaderA)
+        mShader.setInputShader("imageB", mShaderB)
+        mShader.setIntUniform("imageDimensions", width, height)
+        mShader.setFloatUniform("progress", mCurrentProgress)
+
+        mPaint.shader = mShader
+        canvas.drawRect(0f, 0f, width.toFloat(), height.toFloat(), mPaint)
+    }
+
+    private companion object {
+        const val AGSL = """
+        uniform shader imageA;
+        uniform shader imageB;
+        uniform ivec2 imageDimensions;
+        uniform float progress;
+
+        const vec2 iSize = vec2(48.0, 48.0);
+        const float iDir = 0.5;
+        const  float iRand = 0.81;
+
+        float hash12(vec2 p) {
+            vec3 p3  = fract(vec3(p.xyx) * .1031);
+            p3 += dot(p3, p3.yzx + 33.33);
+            return fract((p3.x + p3.y) * p3.z);
+        }
+
+        float ramp(float2 p) {
+          return mix(hash12(p),
+                     dot(p/vec2(imageDimensions), float2(iDir, 1 - iDir)),
+                     iRand);
+        }
+
+        half4 main(float2 p) {
+          float2 lowRes = p / iSize;
+          float2 cellCenter = (floor(lowRes) + 0.5) * iSize;
+          float2 posInCell = fract(lowRes) * 2 - 1;
+
+          float v = ramp(cellCenter) + progress;
+          float distToCenter = max(abs(posInCell.x), abs(posInCell.y));
+
+          return distToCenter > v ? imageA.eval(p).rgb1 : imageB.eval(p).rgb1;
+        }
+        """
+    }
+}
\ No newline at end of file
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/RenderEffectViewActivity.kt b/tests/HwAccelerationTest/src/com/android/test/hwui/RenderEffectViewActivity.kt
new file mode 100644
index 0000000..06280d2
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/RenderEffectViewActivity.kt
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.hwui
+
+import android.animation.ValueAnimator
+import android.app.Activity
+import android.graphics.Bitmap
+import android.graphics.BitmapShader
+import android.graphics.ImageDecoder
+import android.graphics.Matrix
+import android.graphics.Shader
+import android.graphics.RenderEffect
+import android.graphics.RuntimeShader
+import android.os.Bundle
+import android.view.View
+
+class RenderEffectViewActivity : Activity() {
+
+    private val mDropsShader = RuntimeShader(dropsAGSL, false)
+    private var mDropsAnimator = ValueAnimator.ofFloat(0f, 1f)
+    private var mStartTime = System.currentTimeMillis()
+    private lateinit var mScratchesImage: Bitmap
+    private lateinit var mScratchesShader: BitmapShader
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        setContentView(R.layout.view_runtime_shader)
+
+        val dropsView = findViewById<View>(R.id.CardView)!!
+        dropsView.isClickable = true
+        dropsView.setOnClickListener {
+            if (mDropsAnimator.isRunning) {
+                mDropsAnimator.cancel()
+                dropsView.setRenderEffect(null)
+            } else {
+                mDropsAnimator.start()
+            }
+        }
+
+        val imgSource = ImageDecoder.createSource(resources, R.drawable.scratches)
+        mScratchesImage = ImageDecoder.decodeBitmap(imgSource)
+        mScratchesShader = BitmapShader(mScratchesImage,
+                                        Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
+
+        mDropsAnimator.duration = 1000
+        mDropsAnimator.repeatCount = ValueAnimator.INFINITE
+        mDropsAnimator.addUpdateListener { _ ->
+            val viewWidth = dropsView.width.toFloat()
+            val viewHeight = dropsView.height.toFloat()
+            val scratchesMatrix = Matrix()
+            scratchesMatrix.postScale(viewWidth / mScratchesImage.width,
+                    viewHeight / mScratchesImage.height)
+            mScratchesShader.setLocalMatrix(scratchesMatrix)
+
+            mDropsShader.setInputShader("scratches", mScratchesShader)
+            mDropsShader.setFloatUniform("elapsedSeconds",
+                                    (System.currentTimeMillis() - mStartTime) / 1000f)
+            mDropsShader.setFloatUniform("viewDimensions", viewWidth, viewHeight)
+
+            val dropsEffect = RenderEffect.createRuntimeShaderEffect(mDropsShader, "background")
+            val blurEffect = RenderEffect.createBlurEffect(10f, 10f, Shader.TileMode.CLAMP)
+
+            dropsView.setRenderEffect(RenderEffect.createChainEffect(dropsEffect, blurEffect))
+        }
+    }
+
+    private companion object {
+        const val dropsAGSL = """
+            uniform float elapsedSeconds;
+            uniform vec2 viewDimensions;
+            uniform shader background;
+            uniform shader scratches;
+
+            vec2 dropsUV(vec2 fragCoord ) {
+                vec2 uv = fragCoord.xy / viewDimensions.xy; // 0 <> 1
+                vec2 offs = vec2(0.);
+                return (offs + uv).xy;
+            }
+
+            const vec3  iFrostColorRGB = vec3(0.5, 0.5, 0.5);
+            const float iFrostColorAlpha = .3;
+
+            half4 main(float2 fragCoord) {
+                half4 bg = background.eval(dropsUV(fragCoord)*viewDimensions.xy);
+                float2 scratchCoord = fragCoord.xy / viewDimensions.xy;;
+                scratchCoord += 1.5;
+                scratchCoord = mod(scratchCoord, 1);
+                half scratch = scratches.eval(scratchCoord*viewDimensions.xy).r;
+                bg.rgb = mix(bg.rgb, iFrostColorRGB, iFrostColorAlpha);
+                bg.rgb = mix(bg.rgb, half3(1), pow(scratch,3));
+                return bg;
+            }
+        """
+    }
+}
\ No newline at end of file
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 b21d7b5..426f3be 100644
--- a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
+++ b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
@@ -303,11 +303,14 @@
         assertThat(InstallUtils.getInstalledVersion("test.apex.rebootless")).isEqualTo(1);
         TestApp apex = new TestApp("apex", "test.apex.rebootless", 2,
                 /* isApex= */ true, "test.rebootless_apex_v2.apex");
+        String expectedFailMessage = "Update of APEX package test.apex.rebootless is not allowed "
+                + "for com.android.tests.stagedinstallinternal";
         InstallUtils.commitExpectingFailure(
-                AssertionError.class,
-                "Update of APEX package test.apex.rebootless is not allowed "
-                        + "for com.android.tests.stagedinstallinternal",
+                AssertionError.class, expectedFailMessage,
                 Install.single(apex).setBypassAllowedApexUpdateCheck(false).setStaged());
+        InstallUtils.commitExpectingFailure(
+                AssertionError.class, expectedFailMessage,
+                Install.multi(apex).setBypassAllowedApexUpdateCheck(false).setStaged());
     }
 
     @Test
@@ -315,11 +318,14 @@
         assertThat(InstallUtils.getInstalledVersion("test.apex.rebootless")).isEqualTo(1);
         TestApp apex = new TestApp("apex", "test.apex.rebootless", 2,
                 /* isApex= */ true, "test.rebootless_apex_v2.apex");
+        String expectedFailMessage = "Update of APEX package test.apex.rebootless is not allowed "
+                + "for com.android.tests.stagedinstallinternal";
         InstallUtils.commitExpectingFailure(
-                AssertionError.class,
-                "Update of APEX package test.apex.rebootless is not allowed "
-                        + "for com.android.tests.stagedinstallinternal",
+                AssertionError.class, expectedFailMessage,
                 Install.single(apex).setBypassAllowedApexUpdateCheck(false));
+        InstallUtils.commitExpectingFailure(
+                AssertionError.class, expectedFailMessage,
+                Install.multi(apex).setBypassAllowedApexUpdateCheck(false));
     }
 
     @Test
@@ -327,11 +333,14 @@
         assertThat(InstallUtils.getInstalledVersion("test.apex.rebootless")).isEqualTo(1);
         TestApp apex = new TestApp("apex", "test.apex.rebootless", 2,
                 /* isApex= */ true, "test.rebootless_apex_v2.apex");
+        String expectedFailMessage = "Update of APEX package test.apex.rebootless is not allowed "
+                + "for com.android.tests.stagedinstallinternal";
         InstallUtils.commitExpectingFailure(
-                AssertionError.class,
-                "Update of APEX package test.apex.rebootless is not allowed "
-                        + "for com.android.tests.stagedinstallinternal",
+                AssertionError.class, expectedFailMessage,
                 Install.single(apex).setBypassAllowedApexUpdateCheck(false).setStaged());
+        InstallUtils.commitExpectingFailure(
+                AssertionError.class, expectedFailMessage,
+                Install.multi(apex).setBypassAllowedApexUpdateCheck(false).setStaged());
     }
 
     @Test
@@ -339,11 +348,14 @@
         assertThat(InstallUtils.getInstalledVersion("test.apex.rebootless")).isEqualTo(1);
         TestApp apex = new TestApp("apex", "test.apex.rebootless", 2,
                 /* isApex= */ true, "test.rebootless_apex_v2.apex");
+        String expectedFailMessage = "Update of APEX package test.apex.rebootless is not allowed "
+                + "for com.android.tests.stagedinstallinternal";
         InstallUtils.commitExpectingFailure(
-                AssertionError.class,
-                "Update of APEX package test.apex.rebootless is not allowed "
-                        + "for com.android.tests.stagedinstallinternal",
+                AssertionError.class, expectedFailMessage,
                 Install.single(apex).setBypassAllowedApexUpdateCheck(false));
+        InstallUtils.commitExpectingFailure(
+                AssertionError.class, expectedFailMessage,
+                Install.multi(apex).setBypassAllowedApexUpdateCheck(false));
     }
 
     @Test
@@ -467,8 +479,7 @@
         // Query proper module name
         result = getPackageManagerNative().getStagedApexInfo(TEST_APEX_PACKAGE_NAME);
         assertThat(result.moduleName).isEqualTo(TEST_APEX_PACKAGE_NAME);
-        assertThat(result.hasBootClassPathJars).isTrue();
-        assertThat(result.hasSystemServerClassPathJars).isTrue();
+        assertThat(result.hasClassPathJars).isTrue();
         InstallUtils.openPackageInstallerSession(sessionId).abandon();
     }
 
diff --git a/tools/fonts/fontchain_linter.py b/tools/fonts/fontchain_linter.py
index e181c62..fe2b018 100755
--- a/tools/fonts/fontchain_linter.py
+++ b/tools/fonts/fontchain_linter.py
@@ -13,41 +13,54 @@
 EMOJI_VS = 0xFE0F
 
 LANG_TO_SCRIPT = {
+    'af': 'Latn',
     'as': 'Beng',
+    'am': 'Latn',
     'be': 'Cyrl',
     'bg': 'Cyrl',
     'bn': 'Beng',
+    'cs': 'Latn',
     'cu': 'Cyrl',
     'cy': 'Latn',
     'da': 'Latn',
     'de': 'Latn',
+    'el': 'Latn',
     'en': 'Latn',
     'es': 'Latn',
     'et': 'Latn',
     'eu': 'Latn',
     'fr': 'Latn',
     'ga': 'Latn',
+    'gl': 'Latn',
     'gu': 'Gujr',
     'hi': 'Deva',
     'hr': 'Latn',
     'hu': 'Latn',
     'hy': 'Armn',
+    'it': 'Latn',
     'ja': 'Jpan',
+    'ka': 'Latn',
     'kn': 'Knda',
     'ko': 'Kore',
     'la': 'Latn',
+    'lt': 'Latn',
+    'lv': 'Latn',
     'ml': 'Mlym',
     'mn': 'Cyrl',
     'mr': 'Deva',
     'nb': 'Latn',
+    'nl': 'Latn',
     'nn': 'Latn',
     'or': 'Orya',
     'pa': 'Guru',
     'pt': 'Latn',
+    'sk': 'Latn',
     'sl': 'Latn',
+    'sq': 'Latn',
     'ta': 'Taml',
     'te': 'Telu',
     'tk': 'Latn',
+    'uk': 'Latn',
 }
 
 def lang_to_script(lang_code):
diff --git a/tools/lint/README.md b/tools/lint/README.md
index df2fe2a..2b6d65b 100644
--- a/tools/lint/README.md
+++ b/tools/lint/README.md
@@ -41,6 +41,37 @@
   `defaults` field, e.g. `platform_service_defaults`, you can add the `lint` property to that common
   module instead of adding it in every module.
 
+## Create or update a baseline
+
+Baseline files can be used to silence known errors (and warnings) that are deemed to be safe. When
+there is a lint-baseline.xml file in the root folder of the java library, soong will
+automatically use it. You can override the file using lint properties too.
+
+```
+java_library {
+    lint: {
+        baseline_filename: "my-baseline.xml", // default: lint-baseline.xml;
+    }
+}
+```
+
+When using soong to create a lint report (as described above), it also creates a reference
+baseline file. This contains all lint errors and warnings that were found. So the next time
+you run lint, if you use this baseline file, there should be 0 findings.
+
+After the previous invocation, you can find the baseline here:
+
+```
+out/soong/.intermediates/frameworks/base/services/autofill/services.autofill/android_common/lint/lint-baseline.xml
+```
+
+As noted above, this baseline file contains warnings too, which might be undesirable. For example,
+CI tools might surface these warnings in code reviews. In order to create this file without
+warnings, we need to pass another flag to lint: `--nowarn`. The easiest way to do this is to
+locally change the soong code in
+[lint.go](http://cs/aosp-master/build/soong/java/lint.go;l=451;rcl=2e778d5bc4a8d1d77b4f4a3029a4a254ad57db75)
+adding `cmd.Flag("--nowarn")` and running lint again.
+
 ## Documentation
 
 - [Android Lint Docs](https://googlesamples.github.io/android-custom-lint-rules/)